Core Rule Set: a repository's name passes in the adopt form's id (closes #365) #367
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user