Compare commits

..
1 Commits
Author SHA1 Message Date
clawbot 3044b823f3 Core Rule Set: a repository's name passes in the adopt form's id (closes #365)
check / check (push) Waiting to run
While bodies are read, the admin forms that adopt or delete an unadopted
repository were refused when the repository's name held a command or a
system file's name, such as alice/python3-app, alice/powershell-scripts or
alice/.profile. id there now skips 930120, 932120 and 932260, on gitea's
/-/admin/repos/unadopted and Forgejo's /admin/repos/unadopted.

Model: opus-5-5
2026-11-12 00:57:39 +00:00
3 changed files with 70 additions and 6 deletions

No files matched your search

+8 -3
View File
@@ -812,9 +812,9 @@ The changes hold in front of every app, and no setting undoes them:
a push reuses a layer, `from` names the image the layer comes from. An image a push reuses a layer, `from` names the image the layer comes from. An image
such as `owner/python3-app` would have that push refused. such as `owner/python3-app` would have that push refused.
8. On gitea's paths, some fields skip the rules that refused ordinary gitea 8. On gitea's paths, some fields skip the rules that refused ordinary gitea
requests there. They are the fields where gitea sends a search, a file name requests there. They are the fields where gitea sends a search, a file name,
or a branch name. `internal/coreruleset/gitea.conf` lists each rule and the a branch name or a repository's name. `internal/coreruleset/gitea.conf` lists
request it refused. The fields are: each rule and the request it refused. The fields are:
- `q` on gitea's searches of code, of issues and pull requests, and of - `q` on gitea's searches of code, of issues and pull requests, and of
commits. A code search holds code, such as `<script>`, commits. A code search holds code, such as `<script>`,
`SELECT * FROM users WHERE` or `../`. `SELECT * FROM users WHERE` or `../`.
@@ -884,6 +884,11 @@ The changes hold in front of every app, and no setting undoes them:
- to start a release from a tag; - to start a release from a tag;
- to edit a branch protection rule; - to edit a branch protection rule;
- to list a directory's last commits. - to list a directory's last commits.
- `id` of the admin forms that adopt or delete an unadopted repository, for
the lists of system files and command names (930120, 932120, 932260). `id`
holds the repository's owner and name, such as `alice/python3-app` or
`alice/.profile`. gitea serves the forms at `/-/admin/repos/unadopted` and
Forgejo at `/admin/repos/unadopted`.
- The `Content-Range` header of an artifact upload from - The `Content-Range` header of an artifact upload from
`actions/upload-artifact@v3` (920450). `actions/upload-artifact@v3` (920450).
- The passwords in a body, for each rule that random passwords set off. The - The passwords in a body, for each rule that random passwords set off. The
+45
View File
@@ -2421,6 +2421,51 @@ func TestGiteaBodiesTheCoreRuleSetRefuses(t *testing.T) {
) )
} }
func TestGiteaFormsThatAdoptARepositoryLetItsNameThrough(t *testing.T) {
t.Parallel()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
crs := readingBodies(t)
// gitea's path, then Forgejo's.
for _, path := range []string{
"/-/admin/repos/unadopted",
"/admin/repos/unadopted",
} {
r := request{http.MethodPost, path, []string{formData}}
for _, action := range []string{"adopt", "delete"} {
for _, name := range []string{
"alice%2Fpython3-app",
"alice%2Fpowershell-scripts",
"alice%2F.profile",
} {
body := "id=" + name + "&action=" + action + "&q=&page=1"
wantBody(t, crs, r, body, coreruleset.Result{}, body)
}
}
// Attacks in id are still refused.
for _, attack := range []string{
sqlInjection,
scriptInjection,
commandInjection,
"..%2F..%2Fetc%2Fpasswd",
} {
body := "id=" + attack + "&action=adopt&q=&page=1"
if got, _ := inspectBody(t, crs, r, body); got.Score < threshold {
t.Errorf("POST %s %s let through: %+v", path, body, got)
}
}
}
// On another path, id keeps those rules.
r := request{http.MethodPost, "/-/admin/repos", []string{formData}}
body := "id=alice%2Fpython3-app&action=adopt&q=&page=1"
wantBody(t, crs, r, body, matched(932260), body)
}
func TestTypesEndingInXMLOrJSONAndTextJSONAreRead(t *testing.T) { func TestTypesEndingInXMLOrJSONAndTextJSONAreRead(t *testing.T) {
t.Parallel() t.Parallel()
+17 -3
View File
@@ -1,8 +1,9 @@
# The eighth change: on gitea's paths, some fields skip the rules that refused # The eighth change: on gitea's paths, some fields skip the rules that refused
# ordinary gitea requests there. They are the fields where gitea sends a search, # ordinary gitea requests there. They are the fields where gitea sends a search,
# a file name or a branch name. Each exclusion runs with the request, before the # a file name, a branch name or a repository's name. Each exclusion runs with
# rules it switches off, those of phase 1 included, so this file is loaded before # the request, before the rules it switches off, those of phase 1 included, so
# the Core Rule Set's rules. Each comment names a request the rule refused. # this file is loaded before the Core Rule Set's rules. Each comment names a
# request the rule refused.
# gitea's searches of code, of issues and pull requests, and of commits send the # gitea's searches of code, of issues and pull requests, and of commits send the
# text searched for in q, which skips these rules there: # text searched for in q, which skips these rules there:
@@ -322,6 +323,19 @@ SecRule REQUEST_FILENAME \
"id:900640,phase:1,pass,nolog,\ "id:900640,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=920450;REQUEST_HEADERS_NAMES:Content-Range" ctl:ruleRemoveTargetById=920450;REQUEST_HEADERS_NAMES:Content-Range"
# The admin forms that adopt or delete an unadopted repository send its owner
# and name in id, as alice/python3-app. id skips these rules there:
# 930120: alice/.profile
# 932120: alice/powershell-scripts
# 932260: alice/python3-app
# gitea serves the forms at /-/admin/repos/unadopted and Forgejo at
# /admin/repos/unadopted.
SecRule REQUEST_FILENAME "@rx ^/(?:-/)?admin/repos/unadopted$" \
"id:900645,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:id,\
ctl:ruleRemoveTargetById=932120;ARGS:id,\
ctl:ruleRemoveTargetById=932260;ARGS:id"
# The passwords skip each rule that random passwords set off: # The passwords skip each rule that random passwords set off:
# password: signing in, signing up, linking an account, activating an account, # password: signing in, signing up, linking an account, activating an account,
# resetting or changing the password, deleting an account, and creating or # resetting or changing the password, deleting an account, and creating or