Core Rule Set: a repository's name passes in the adopt form's id (closes #365) #367

Open
clawbot wants to merge 1 commits from issue-365-adopt-form-repository-names into next
pull from: issue-365-adopt-form-repository-names
4 changed files with 100 additions and 10 deletions
Showing only changes of commit 52b5fcb9d2 - Show all commits

No files matched your search

+4 -4
View File
@@ -587,11 +587,11 @@ client's limits by tag. See "Request tags" in [`SPEC.md`](SPEC.md).
- These apps work out of the box at the default settings, and their recorded
ordinary requests pass the Core Rule Set:
- gitea: git over HTTP and sign-in through Git Credential Manager get
through. On gitea's own paths, its searches, file names and branch names
do too.
through. On gitea's own paths, its searches, file names, branch names and
repository names do too.
- Forgejo: git over HTTP and its container and package registries get
through. On Forgejo's own paths, its searches, file names and branch names
do too.
through. On Forgejo's own paths, its searches, file names, branch names
and repository names do too.
- WordPress: saving a post from the block editor gets through. On
WordPress's own paths, its searches, names and file names do too.
- Drupal: on Drupal's own paths, the page to return to, its searches and its
+12 -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
such as `owner/python3-app` would have that push refused.
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
or a branch name. `internal/coreruleset/gitea.conf` lists each rule and the
request it refused. The fields are:
requests there. They are the fields where gitea sends a search, a file name,
a branch name or a repository's name. `internal/coreruleset/gitea.conf` lists
each rule and the request it refused. The fields are:
- `q` on gitea's searches of code, of issues and pull requests, and of
commits. A code search holds code, such as `<script>`,
`SELECT * FROM users WHERE` or `../`.
@@ -884,6 +884,15 @@ 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.
- `id` of the forms that adopt or delete an unadopted repository, for the
rules that refused repository names (930120, 932120, 932160, 932260). `id`
holds the repository's name, such as `python3-app` or `.profile`. The
admin forms put the owner in front. There the rule for shell paths refused
`robin/assets`, which holds `bin/as`. The forms post to these paths:
- `/-/admin/repos/unadopted`, gitea's admin form;
- `/admin/repos/unadopted`, Forgejo's admin form;
- `/user/settings/repos/unadopted`, the form in a user's settings, on
both.
- 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
+61
View File
@@ -2421,6 +2421,67 @@ func TestGiteaBodiesTheCoreRuleSetRefuses(t *testing.T) {
)
}
func TestGiteaFormsThatAdoptARepositoryLetItsNameThrough(t *testing.T) {
t.Parallel()
const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default
crs := readingBodies(t)
// The admin forms send the repository's owner and name in id, and the
// form in a user's settings only its name. robin/assets holds bin/as, a
// shell path.
ownerAndName := []string{
"alice%2Fpython3-app",
"alice%2Fpowershell-scripts",
"alice%2F.profile",
"robin%2Fassets",
}
for _, form := range []struct {
path string
ids []string
}{
{"/-/admin/repos/unadopted", ownerAndName}, // gitea's
{"/admin/repos/unadopted", ownerAndName}, // Forgejo's
{
"/user/settings/repos/unadopted", // gitea's and Forgejo's
[]string{"python3-app", "powershell-scripts", ".profile"},
},
} {
r := request{http.MethodPost, form.path, []string{formData}}
for _, action := range []string{"adopt", "delete"} {
for _, id := range form.ids {
body := "id=" + id + "&action=" + action
wantBody(t, crs, r, body, coreruleset.Result{}, body)
}
}
// Another field keeps those rules.
body := "id=" + form.ids[0] + "&action=adopt&page=python3"
wantBody(t, crs, r, body, matched(932260), body)
// Attacks in id are still refused.
for _, attack := range []string{
sqlInjection,
scriptInjection,
commandInjection,
"..%2F..%2Fetc%2Fpasswd",
} {
body := "id=" + attack + "&action=adopt"
if got, _ := inspectBody(t, crs, r, body); got.Score < threshold {
t.Errorf("POST %s %s let through: %+v", form.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) {
t.Parallel()
+23 -3
View File
@@ -1,8 +1,9 @@
# 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,
# a file name or a branch name. Each exclusion runs with the request, before the
# rules it switches off, those of phase 1 included, so this file is loaded before
# the Core Rule Set's rules. Each comment names a request the rule refused.
# a file name, a branch name or a repository's name. Each exclusion runs with
# the request, before the rules it switches off, those of phase 1 included, so
# 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
# text searched for in q, which skips these rules there:
@@ -322,6 +323,25 @@ SecRule REQUEST_FILENAME \
"id:900640,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=920450;REQUEST_HEADERS_NAMES:Content-Range"
# The forms that adopt or delete an unadopted repository send its name in id.
# The admin forms put its owner in front, as alice/python3-app. id skips these
# rules there:
# 930120: alice/.profile
# 932120: alice/powershell-scripts
# 932160: robin/assets, which holds bin/as
# 932260: alice/python3-app
# The forms post to these paths:
# /-/admin/repos/unadopted: gitea's admin form
# /admin/repos/unadopted: Forgejo's admin form
# /user/settings/repos/unadopted: the form in a user's settings, on both
SecRule REQUEST_FILENAME \
"@rx ^/(?:(?:-/)?admin|user/settings)/repos/unadopted$" \
"id:900645,phase:1,pass,nolog,\
ctl:ruleRemoveTargetById=930120;ARGS:id,\
ctl:ruleRemoveTargetById=932120;ARGS:id,\
ctl:ruleRemoveTargetById=932160;ARGS:id,\
ctl:ruleRemoveTargetById=932260;ARGS:id"
# The passwords skip each rule that random passwords set off:
# password: signing in, signing up, linking an account, activating an account,
# resetting or changing the password, deleting an account, and creating or