From 9a7069197c3224d5198926e6e9f35d818deb3869 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 7 Nov 2026 15:44:04 -1000 Subject: Test every scanned key that waits on trust Only head-content and logo-link were tried, so logo, clone-url and both module-link forms could have been taken from a repository's own cgitrc unnoticed. A trusted control shows each value would reach the page, and the refused disk readmes are now checked against a file that would show if read. --- tests/t0303-robustness.sh | 102 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/tests/t0303-robustness.sh b/tests/t0303-robustness.sh index c0e7c96..bb405f1 100755 --- a/tests/t0303-robustness.sh +++ b/tests/t0303-robustness.sh @@ -97,36 +97,92 @@ test_expect_success 'a valueless or broken git config in a scanned repository is grep "Ignoring unreadable config in $PWD/scan/a.git/config" err ' -test_expect_success 'only descriptive keys are taken from a scanned repository' ' +# A repository's own cgitrc belongs to whoever can push to it, and each value +# below would reach the page once trusted. clone-url is even expanded from +# the request's environment, a visitor's cookie among it, into a page the +# cache then serves to others. +test_expect_success 'set up a scanned repository setting every key that waits on trust' ' git clone -q --bare repos/rob/.git scan/b.git && + mkrepo scankeys/k 1 && + sub=$(git -C scankeys/k rev-parse HEAD) && + git -C scankeys/k update-index --add --cacheinfo 160000,$sub,sub && + git -C scankeys/k update-index --add --cacheinfo 160000,$sub,other && + git -C scankeys/k commit -q -m gitlinks && + write_script evil-filter.sh <<-\EOF && + echo "evil filter" + cat + EOF + cat >scankeys/k/.git/cgitrc <<-EOF && + desc=from the repo + readme=master:file-1 + about-filter=exec:$PWD/evil-filter.sh + head-content= + logo=/evil/logo.png + logo-link=https://evil.example/logo-link + clone-url=https://evil.example/clone + module-link=https://evil.example/module/%s + module-link.sub=https://evil.example/path/%s + EOF + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "scan-path=$PWD/scankeys" + } >scankeysrc && { - echo "desc=from the repo" && - echo "readme=master:file-1" && - echo "head-content=" && - echo "logo-link=javascript:alert(2)" - } >scan/b.git/cgitrc && - cgit_rc gitcfgrc "url=b.git/about/" >tmp 2>err && - grep "from the repo" tmp && - grep "pre class=.plaintext." tmp && - ! grep "alert(" tmp && - grep "Ignoring head-content in $PWD/scan/b.git/: trust-scan-config is not set" err && - grep "Ignoring logo-link in " err + echo "trust-scan-config=1" && + cat scankeysrc + } >scankeystrustrc ' -test_expect_success 'a filesystem readme from a scanned repository is refused' ' - echo "readme=/etc/hosts" >scan/b.git/cgitrc && - cgit_rc gitcfgrc "url=b.git/about/" >tmp 2>err && - grep "Ignoring readme in " err +test_expect_success 'only descriptive keys are taken from a scanned repository' ' + for page in about/ "" tree/ + do + cgit_rc scankeysrc "url=k/$page" >tmp 2>err && + test_grep "^Status: 200" tmp && + test_grep "

from the repo

" tmp && + test_grep ! "evil" tmp && + test_grep ! "alert(" tmp || return 1 + done && + for key in about-filter head-content logo logo-link clone-url module-link module-link.sub + do + test_grep "Ignoring $key in $PWD/scankeys/k/.git/: trust-scan-config is not set" err || return 1 + done && + cgit_rc scankeysrc "url=k/about/" >tmp && + test_grep "
1$" tmp
+'
+
+test_expect_success 'with trust-scan-config the same keys apply' '
+	sub=$(git -C scankeys/k rev-parse HEAD~1) &&
+	cgit_ok scankeystrustrc "url=k/about/" >tmp &&
+	test_grep "^$" tmp &&
+	test_grep "evil filter$" tmp &&
+	cgit_ok scankeystrustrc "url=k/" >tmp &&
+	test_grep "https://evil.example/clone" tmp &&
+	cgit_ok scankeystrustrc "url=k/tree/" >tmp &&
+	test_grep "href=.https://evil.example/path/$sub.>sub" tmp &&
+	test_grep "href=.https://evil.example/module/other.>other" tmp
 '
 
-# A colon with nothing after it names no ref, so the setting is a path on
-# disk and has to wait on trust like any other.
-test_expect_success 'a readme ending in a colon is refused like a path on disk' '
+# A path on the server waits on trust, and so does a readme ending in a
+# colon, which names no ref and is read as a path too.
+test_expect_success 'a filesystem readme from a scanned repository is refused' '
+	echo "outside the repository" >outside &&
 	echo "outside the repository" >"scan/outside:" &&
-	echo "readme=../outside:" >scan/b.git/cgitrc &&
-	cgit_rc gitcfgrc "url=b.git/about/" >tmp 2>err &&
-	grep "Ignoring readme in " err &&
-	! grep "outside the repository" tmp
+	{
+		echo "trust-scan-config=1" &&
+		cat gitcfgrc
+	} >gitcfgtrustrc &&
+	for readme in "$PWD/outside" ../outside:
+	do
+		echo "readme=$readme" >scan/b.git/cgitrc &&
+		cgit_rc gitcfgrc "url=b.git/about/" >tmp 2>err &&
+		test_grep "^Status: 302" tmp &&
+		test_grep "Ignoring readme in $PWD/scan/b.git/: trust-scan-config is not set" err &&
+		cgit_rc gitcfgtrustrc "url=b.git/about/" >tmp &&
+		test_grep "^Status: 200" tmp &&
+		test_grep "outside the repository" tmp || return 1
+	done
 '
 
 # The readme list is read as a page is served rather than copied at the
-- 
cgit 2.12.1