Core Rule Set: a repository's name passes in the adopt form's id (closes #365)
check / check (push) Successful in 3m50s
check / check (push) Successful in 3m50s
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
This commit is contained in:
1 parent
0b23352767
commit
3044b823f3
3 files changed
+70
-6
No files matched your search
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user