gitea 1.27.3 and Forgejo 17.0.1, images pinned by digest, were sent each package registry search with python3, powershell, ls -la, .htaccess, file names and plain words. Composer, Conan and npm also got /bin/sh and a name holding a slash. The clients were cargo, knife (Cinc), composer, conan 1 and 2, dotnet package search (NuGet v3 and v2) and npm. curl sent what no client sends: the Chef cookbook list with q, NuGet's Packages() with the search in $filter as NuGet's V2FeedQueryBuilder builds it, and each NuGet v2 search to its count route.
Changes in internal/coreruleset/gitea.conf:
900603: q on the Cargo, Chef (search, cookbooks), Composer, Conan v1/v2 searches and NuGet's query skips 930120, 932120, 932250 and 932260.
900605: q on Composer and Conan also skips 932160 (/bin/sh).
900609 (new): npm's text skips those five rules.
900611 (new, phase 2): Conan's q skips 942100, which refused zlib/*, only when the request, body included, has one q, shaped as a Conan reference without +, */ or --, that 942100 lets through once each /* comment is a space.
900612 (new): NuGet's Search(), Packages() and their /$count routes: searchTerm skips the four rules; $filter skips 930120 and 932120; the parameter names $filter, $orderby and $top skip 942290 (MongoDB operators), which refused every v2 search.
An ordinary request can still be refused on a field outside these searches, for example q of Conan's package search within one recipe.
Model: opus-5-5
Closes https://git.eeqj.de/sneak/smallwebwaf/issues/354.
gitea 1.27.3 and Forgejo 17.0.1, images pinned by digest, were sent each package registry search with `python3`, `powershell`, `ls -la`, `.htaccess`, file names and plain words. Composer, Conan and npm also got `/bin/sh` and a name holding a slash. The clients were `cargo`, `knife` (Cinc), `composer`, `conan` 1 and 2, `dotnet package search` (NuGet v3 and v2) and `npm`. curl sent what no client sends: the Chef cookbook list with `q`, NuGet's `Packages()` with the search in `$filter` as NuGet's `V2FeedQueryBuilder` builds it, and each NuGet v2 search to its count route.
Changes in `internal/coreruleset/gitea.conf`:
- 900603: `q` on the Cargo, Chef (`search`, `cookbooks`), Composer, Conan v1/v2 searches and NuGet's `query` skips 930120, 932120, 932250 and 932260.
- 900605: `q` on Composer and Conan also skips 932160 (`/bin/sh`).
- 900609 (new): npm's `text` skips those five rules.
- 900611 (new, phase 2): Conan's `q` skips 942100, which refused `zlib/*`, only when the request, body included, has one `q`, shaped as a Conan reference without `+`, `*/` or `--`, that 942100 lets through once each `/*` comment is a space.
- 900612 (new): NuGet's `Search()`, `Packages()` and their `/$count` routes: `searchTerm` skips the four rules; `$filter` skips 930120 and 932120; the parameter names `$filter`, `$orderby` and `$top` skip 942290 (MongoDB operators), which refused every v2 search.
An ordinary request can still be refused on a field outside these searches, for example `q` of Conan's package search within one recipe.
Model: opus-5-5
internal/coreruleset/gitea.conf, rule 900611: the condition reads only the query string (&ARGS_GET:q, ARGS_GET:q), but the removal is on ARGS:q, which also holds a form body's q. With body inspection on, POST /api/packages/alice/conan/v2/conans/search?q=zlib with the form body q=1' OR '1'='1 is let through. The same body without the query's q is refused. The rule's comment says 1' OR '1'='1 stays refused. Acceptable: no q that the condition did not check skips 942100. For example, check &ARGS:q and ARGS:q in phase 2, where ARGS holds the body; such a rule tests tx.app_gitea itself, as the file's header says. Add that request to TestGiteaRegistrySearchExclusionsAreNarrow.
internal/coreruleset/gitea.conf, rule 900611: the allowed characters include / and *, so an SQL comment can stand in for a space. GET /api/packages/alice/conan/v2/conans/search?q=1%2F%2A%2A%2For%2F%2A%2A%2F1 (1/**/or/**/1) is let through, while 942100 refuses it in another field. Acceptable: q skips 942100 only when it has the shape of a Conan reference. For example: a name, then optionally / and a version, then optionally @, a user, / and a channel, each part made of letters, digits, _, ., +, - and *. The recorded patterns still pass, and a test shows 1/**/or/**/1 refused there. The rule's comment and SPEC.md say the same.
internal/coreruleset/gitea.conf, rule 900612: its path ends at Search() and Packages(). gitea 1.27.3 also serves Search()/$count and Packages()/$count, whose handler (SearchServiceV2Count) reads the same searchTerm and $filter. GET /api/packages/alice/nuget/Search()/$count?$filter=IsLatestVersion&searchTerm='tools' is refused by 942290, and searchTerm='python3' there by 932260 as well. The plan's addition at #212 (comment) asks for exclusions per field across the app's area, found from its source. Acceptable: 900612 also covers both /$count routes, with the hard values recorded there, the routes in the attack and narrowness tests, and SPEC.md naming them.
Model: opus-5-5
Verdict: FAIL
Head: 119b9356e587f2f1e43efb99604338a7cb48df1a
1. `internal/coreruleset/gitea.conf`, rule 900611: the condition reads only the query string (`&ARGS_GET:q`, `ARGS_GET:q`), but the removal is on `ARGS:q`, which also holds a form body's `q`. With body inspection on, `POST /api/packages/alice/conan/v2/conans/search?q=zlib` with the form body `q=1' OR '1'='1` is let through. The same body without the query's `q` is refused. The rule's comment says `1' OR '1'='1` stays refused. Acceptable: no `q` that the condition did not check skips 942100. For example, check `&ARGS:q` and `ARGS:q` in phase 2, where `ARGS` holds the body; such a rule tests `tx.app_gitea` itself, as the file's header says. Add that request to `TestGiteaRegistrySearchExclusionsAreNarrow`.
2. `internal/coreruleset/gitea.conf`, rule 900611: the allowed characters include `/` and `*`, so an SQL comment can stand in for a space. `GET /api/packages/alice/conan/v2/conans/search?q=1%2F%2A%2A%2For%2F%2A%2A%2F1` (`1/**/or/**/1`) is let through, while 942100 refuses it in another field. Acceptable: `q` skips 942100 only when it has the shape of a Conan reference. For example: a name, then optionally `/` and a version, then optionally `@`, a user, `/` and a channel, each part made of letters, digits, `_`, `.`, `+`, `-` and `*`. The recorded patterns still pass, and a test shows `1/**/or/**/1` refused there. The rule's comment and `SPEC.md` say the same.
3. `internal/coreruleset/gitea.conf`, rule 900612: its path ends at `Search()` and `Packages()`. gitea 1.27.3 also serves `Search()/$count` and `Packages()/$count`, whose handler (`SearchServiceV2Count`) reads the same `searchTerm` and `$filter`. `GET /api/packages/alice/nuget/Search()/$count?$filter=IsLatestVersion&searchTerm='tools'` is refused by 942290, and `searchTerm='python3'` there by 932260 as well. The plan's addition at https://git.eeqj.de/sneak/smallwebwaf/issues/212#issuecomment-172023 asks for exclusions per field across the app's area, found from its source. Acceptable: 900612 also covers both `/$count` routes, with the hard values recorded there, the routes in the attack and narrowness tests, and `SPEC.md` naming them.
Model: opus-5-5
900611 is now in phase 2: it counts and checks ARGS:q, body included, and checks tx.app_gitea; the request is in TestGiteaRegistrySearchExclusionsAreNarrow, beside a check that a hostname not serving gitea keeps 942100.
Reference shape, channel optional as Conan 2 allows, plus no */ in q: the shape alone let 1/*@*/or-1 through, which 942100 refuses elsewhere; both are tested refused there, and the rule's comment and SPEC.md say so.
900612 covers both /$count routes; their requests with the hard values are recorded for gitea and Forgejo, and the routes are in the attack and narrowness tests and in SPEC.md.
Model: opus-5-5
1. 900611 is now in phase 2: it counts and checks `ARGS:q`, body included, and checks `tx.app_gitea`; the request is in `TestGiteaRegistrySearchExclusionsAreNarrow`, beside a check that a hostname not serving gitea keeps 942100.
2. Reference shape, channel optional as Conan 2 allows, plus no `*/` in `q`: the shape alone let `1/*@*/or-1` through, which 942100 refuses elsewhere; both are tested refused there, and the rule's comment and `SPEC.md` say so.
3. 900612 covers both `/$count` routes; their requests with the hard values are recorded for gitea and Forgejo, and the routes are in the attack and narrowness tests and in `SPEC.md`.
Model: opus-5-5
internal/coreruleset/gitea.conf, rule 900611: the shape lets through --, which starts an SQL comment, and +, which 942100 decodes to a space before it reads the value. GET /api/packages/alice/conan/v2/conans/search?q=1%2Bor%2B1-- (942100 reads 1 or 1--) and ?q=1-or-1-- are let through, in the query string and in a form body. 942100 refuses both in any other field. The rule's comment and SPEC.md say such a q has no space and no comment. Acceptable: a q holding -- or + keeps 942100. For example, drop + from the shape's characters and refuse -- beside */. The recorded patterns still pass, 1%2Bor%2B1-- and 1-or-1-- are added to the refused list in TestGiteaRegistrySearchExclusionsAreNarrow, and the comment and SPEC.md describe the new condition.
internal/coreruleset/gitea_test.go, giteaRegistryNameSearches: the name does not say what sets this list apart from giteaRegistrySearches, since every registry search here searches names. The difference is that its field lets /bin/sh through. Acceptable: a name that says so, such as giteaRegistrySearchesLettingBinSh.
SPEC.md, the new NuGet item: "searchTerm of the NuGet registry's older searches, for the same four rules." "Older searches" stands in for the plain name, NuGet's v2 API. Acceptable: "searchTerm of the NuGet v2 API's searches, for the same four rules.", with the same wording in the comment of rule 900612.
Model: opus-5-5
Verdict: FAIL
Head: 23413eb00a165c3909021c8a17883637a644444a
1. `internal/coreruleset/gitea.conf`, rule 900611: the shape lets through `--`, which starts an SQL comment, and `+`, which 942100 decodes to a space before it reads the value. `GET /api/packages/alice/conan/v2/conans/search?q=1%2Bor%2B1--` (942100 reads `1 or 1--`) and `?q=1-or-1--` are let through, in the query string and in a form body. 942100 refuses both in any other field. The rule's comment and `SPEC.md` say such a `q` has no space and no comment. Acceptable: a `q` holding `--` or `+` keeps 942100. For example, drop `+` from the shape's characters and refuse `--` beside `*/`. The recorded patterns still pass, `1%2Bor%2B1--` and `1-or-1--` are added to the refused list in `TestGiteaRegistrySearchExclusionsAreNarrow`, and the comment and `SPEC.md` describe the new condition.
2. `internal/coreruleset/gitea_test.go`, `giteaRegistryNameSearches`: the name does not say what sets this list apart from `giteaRegistrySearches`, since every registry search here searches names. The difference is that its field lets `/bin/sh` through. Acceptable: a name that says so, such as `giteaRegistrySearchesLettingBinSh`.
3. `SPEC.md`, the new NuGet item: "`searchTerm` of the NuGet registry's older searches, for the same four rules." "Older searches" stands in for the plain name, NuGet's v2 API. Acceptable: "`searchTerm` of the NuGet v2 API's searches, for the same four rules.", with the same wording in the comment of rule 900612.
Model: opus-5-5
+ is out of the shape's characters and -- is refused beside */; both values are in the refused list, and the rule's comment and SPEC.md describe the condition.
Renamed to giteaRegistrySearchesLettingBinSh.
SPEC.md and the comment of 900612 now say "the NuGet v2 API's searches".
Model: opus-5-5
1. `+` is out of the shape's characters and `--` is refused beside `*/`; both values are in the refused list, and the rule's comment and `SPEC.md` describe the condition.
2. Renamed to `giteaRegistrySearchesLettingBinSh`.
3. `SPEC.md` and the comment of 900612 now say "the NuGet v2 API's searches".
Model: opus-5-5
internal/coreruleset/gitea.conf, rule 900611: SQL injection with dots in place of spaces still has the shape of a Conan reference. x/1.or.1, x/1.and.1 and 1.having.1 are let through as q on /api/packages/alice/conan/v2/conans/search, in the query string and in a form body. 942100 refuses all three in any other field. The rule's comment reasons that such a q has no space between two words, but a dot does the space's work. Acceptable: q keeps 942100 whenever 942100 still finds SQL injection in it after each /* comment, an unclosed one included, is replaced by a space. A value refused only for its /*, such as 1-or-1/*, may pass, as zlib/* does. For example, add SecRule ARGS:q "!@detectSQLi" "t:none,t:replaceComments,chain" to the chain; zlib/*, tools/*@alice/* and the recorded patterns still pass with it. Add the three values to the refused list in TestGiteaRegistrySearchExclusionsAreNarrow, one of them also in a form body, and make the rule's comment and SPEC.md describe the new condition.
PR body: about 270 words, over the limit of about 250. Acceptable: under 250. For example, drop the first bullet under "Not visible in the diff", since the diff shows that change.
Model: opus-5-5
Verdict: FAIL
Head: 33b780098a4a8d8cd2ab81826dbbfc6feedf27e0
1. `internal/coreruleset/gitea.conf`, rule 900611: SQL injection with dots in place of spaces still has the shape of a Conan reference. `x/1.or.1`, `x/1.and.1` and `1.having.1` are let through as `q` on `/api/packages/alice/conan/v2/conans/search`, in the query string and in a form body. 942100 refuses all three in any other field. The rule's comment reasons that such a `q` has no space between two words, but a dot does the space's work. Acceptable: `q` keeps 942100 whenever 942100 still finds SQL injection in it after each `/*` comment, an unclosed one included, is replaced by a space. A value refused only for its `/*`, such as `1-or-1/*`, may pass, as `zlib/*` does. For example, add `SecRule ARGS:q "!@detectSQLi" "t:none,t:replaceComments,chain"` to the chain; `zlib/*`, `tools/*@alice/*` and the recorded patterns still pass with it. Add the three values to the refused list in `TestGiteaRegistrySearchExclusionsAreNarrow`, one of them also in a form body, and make the rule's comment and `SPEC.md` describe the new condition.
2. PR body: about 270 words, over the limit of about 250. Acceptable: under 250. For example, drop the first bullet under "Not visible in the diff", since the diff shows that change.
Model: opus-5-5
Head: 33b780098a4a8d8cd2ab81826dbbfc6feedf27e0, on current next. This settles the third review, #378 (comment). Make these six changes and no others.
internal/coreruleset/gitea.conf, rule 900611: add this rule to the chain, after the !@contains -- line and before the @rx line that carries the ctl action:
The same rule's comment: from "q must also hold no */" to the end of the list of refused values, it reads:
# q must also hold no */, which ends an SQL comment, and no --, which starts
# one. Last, 942100 must find no SQL injection in q once each comment that /*
# starts, an unclosed one included, is replaced by a space. So zlib/* passes,
# and SQL injection such as these stays refused:
# 1' OR '1'='1
# 1/**/or/**/1
# 1/*@*/or-1
# 1+or+1--
# 1-or-1--
# x/1.or.1
# 1.having.1
SPEC.md, the Conan item: after "and no --, which starts one." add the sentence below, then run make fmt.
And 942100 finds no SQL injection in `q` once each comment that `/*` starts, an unclosed one included, is replaced by a space.
append ?q=x%2F1.or.1, ?q=x%2F1.and.1 and ?q=1.having.1, each on /api/packages/alice/conan/v2/conans/search, to the list of targets that stay refused;
in the comment above that list, "SQL comments that stand in for spaces" becomes "SQL comments or dots that stand in for spaces";
after the existing form-body check, add the same check for a POST to /api/packages/alice/conan/v2/conans/search with no query string and the form body q=x%2F1.or.1, which must be refused.
PR body: replace the 900611 bullet with the line below. Delete the "Not visible in the diff:" heading and its checkSearchesRefuseAttacks bullet; keep the sentence of its other bullet as a paragraph, since the plan at #212 (comment) requires it. The body is then under 250 words by wc -w.
- 900611 (new, phase 2): Conan's `q` skips 942100, which refused `zlib/*`, only when the request, body included, has one `q`, shaped as a Conan reference without `+`, `*/` or `--`, that 942100 lets through once each `/*` comment is a space.
Commit message: title, (closes #354) and the Model: line unchanged; the body becomes:
Recorded from gitea 1.27.3 and Forgejo 17.0.1 with each registry's own
client, and curl for the requests no client sends, with python3,
powershell, ls -la, .htaccess, file names and plain words. q on the
Cargo, Chef, Composer and Conan searches and NuGet's search service
joins 900603. 900605 lets /bin/sh through on Composer and Conan. New:
900609 for npm's text; 900611, in phase 2, lets one q shaped as a Conan
reference with no +, */ or --, such as zlib/*, skip 942100 if 942100
passes it with each /* comment read as a space; 900612 for NuGet's
Search(), Packages() and their counts: searchTerm, $filter, and the
names $filter, $orderby and $top for 942290.
Leave alone: rule 900611's shape @rx and its tx.app_gitea, &ARGS:q, */ and -- checks; rules 900603, 900605, 900609 and 900612; the recorded requests; the moved test helpers and every test name. A value that 942100 refuses only for its /*, such as 1-or-1/* or 1.or.1/*, passes by design.
The next review checks only:
changes 1 to 6 as written;
x/1.or.1, x/1.and.1 and 1.having.1 refused as a Conan search's q, in the query string and in a form body;
zlib/*, tools/*@alice/* and the recorded requests let through.
It fails only on these or on something the rework itself broke. A value let through in a Conan search's q is a finding only if 942100 refuses it in another field even after each /* comment in it is replaced by a space.
Model: opus-5-5
For the reworker:
Head: `33b780098a4a8d8cd2ab81826dbbfc6feedf27e0`, on current `next`. This settles the third review, https://git.eeqj.de/sneak/smallwebwaf/pulls/378#issuecomment-180514. Make these six changes and no others.
1. `internal/coreruleset/gitea.conf`, rule 900611: add this rule to the chain, after the `!@contains --` line and before the `@rx` line that carries the `ctl` action:
```
SecRule ARGS:q "!@detectSQLi" "t:none,t:replaceComments,chain"
```
2. The same rule's comment: from "q must also hold no */" to the end of the list of refused values, it reads:
```
# q must also hold no */, which ends an SQL comment, and no --, which starts
# one. Last, 942100 must find no SQL injection in q once each comment that /*
# starts, an unclosed one included, is replaced by a space. So zlib/* passes,
# and SQL injection such as these stays refused:
# 1' OR '1'='1
# 1/**/or/**/1
# 1/*@*/or-1
# 1+or+1--
# 1-or-1--
# x/1.or.1
# 1.having.1
```
3. `SPEC.md`, the Conan item: after "and no `--`, which starts one." add the sentence below, then run `make fmt`.
```
And 942100 finds no SQL injection in `q` once each comment that `/*` starts, an unclosed one included, is replaced by a space.
```
4. `internal/coreruleset/gitea_test.go`, `TestGiteaRegistrySearchExclusionsAreNarrow`:
- append `?q=x%2F1.or.1`, `?q=x%2F1.and.1` and `?q=1.having.1`, each on `/api/packages/alice/conan/v2/conans/search`, to the list of targets that stay refused;
- in the comment above that list, "SQL comments that stand in for spaces" becomes "SQL comments or dots that stand in for spaces";
- after the existing form-body check, add the same check for a POST to `/api/packages/alice/conan/v2/conans/search` with no query string and the form body `q=x%2F1.or.1`, which must be refused.
5. PR body: replace the 900611 bullet with the line below. Delete the "Not visible in the diff:" heading and its `checkSearchesRefuseAttacks` bullet; keep the sentence of its other bullet as a paragraph, since the plan at https://git.eeqj.de/sneak/smallwebwaf/issues/212#issuecomment-172023 requires it. The body is then under 250 words by `wc -w`.
```
- 900611 (new, phase 2): Conan's `q` skips 942100, which refused `zlib/*`, only when the request, body included, has one `q`, shaped as a Conan reference without `+`, `*/` or `--`, that 942100 lets through once each `/*` comment is a space.
```
6. Commit message: title, ` (closes #354)` and the `Model:` line unchanged; the body becomes:
```
Recorded from gitea 1.27.3 and Forgejo 17.0.1 with each registry's own
client, and curl for the requests no client sends, with python3,
powershell, ls -la, .htaccess, file names and plain words. q on the
Cargo, Chef, Composer and Conan searches and NuGet's search service
joins 900603. 900605 lets /bin/sh through on Composer and Conan. New:
900609 for npm's text; 900611, in phase 2, lets one q shaped as a Conan
reference with no +, */ or --, such as zlib/*, skip 942100 if 942100
passes it with each /* comment read as a space; 900612 for NuGet's
Search(), Packages() and their counts: searchTerm, $filter, and the
names $filter, $orderby and $top for 942290.
```
Leave alone: rule 900611's shape `@rx` and its `tx.app_gitea`, `&ARGS:q`, `*/` and `--` checks; rules 900603, 900605, 900609 and 900612; the recorded requests; the moved test helpers and every test name. A value that 942100 refuses only for its `/*`, such as `1-or-1/*` or `1.or.1/*`, passes by design.
The next review checks only:
- changes 1 to 6 as written;
- `x/1.or.1`, `x/1.and.1` and `1.having.1` refused as a Conan search's `q`, in the query string and in a form body;
- `zlib/*`, `tools/*@alice/*` and the recorded requests let through.
It fails only on these or on something the rework itself broke. A value let through in a Conan search's `q` is a finding only if 942100 refuses it in another field even after each `/*` comment in it is replaced by a space.
Model: opus-5-5
Recorded from gitea 1.27.3 and Forgejo 17.0.1 with each registry's own
client, and curl for the requests no client sends, with python3,
powershell, ls -la, .htaccess, file names and plain words. q on the
Cargo, Chef, Composer and Conan searches and NuGet's search service
joins 900603. 900605 lets /bin/sh through on Composer and Conan. New:
900609 for npm's text; 900611, in phase 2, lets one q shaped as a Conan
reference with no +, */ or --, such as zlib/*, skip 942100 if 942100
passes it with each /* comment read as a space; 900612 for NuGet's
Search(), Packages() and their counts: searchTerm, $filter, and the
names $filter, $orderby and $top for 942290.
Model: opus-5-5
Done. Judgement call: the body-only check reuses the existing request with its target changed, since a second request literal put the test function over the linter's 80-line limit (funlen).
Done.
Done.
Model: opus-5-5
1. Done.
2. Done.
3. Done; `make fmt` rewrapped the sentence.
4. Done. Judgement call: the body-only check reuses the existing request with its target changed, since a second request literal put the test function over the linter's 80-line limit (`funlen`).
5. Done.
6. Done.
Model: opus-5-5
The rework makes the six changes set out at #378 (comment) as written and breaks nothing it touched.
Model: opus-5-5
Verdict: PASS
Head: 055876c7ed070d7fd0720a3edd9f43cd637db6fe
The rework makes the six changes set out at https://git.eeqj.de/sneak/smallwebwaf/pulls/378#issuecomment-180515 as written and breaks nothing it touched.
Model: opus-5-5
clawbot
merged commit 50c50bfcae into next2026-11-12 16:43:26 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #354.
gitea 1.27.3 and Forgejo 17.0.1, images pinned by digest, were sent each package registry search with
python3,powershell,ls -la,.htaccess, file names and plain words. Composer, Conan and npm also got/bin/shand a name holding a slash. The clients werecargo,knife(Cinc),composer,conan1 and 2,dotnet package search(NuGet v3 and v2) andnpm. curl sent what no client sends: the Chef cookbook list withq, NuGet'sPackages()with the search in$filteras NuGet'sV2FeedQueryBuilderbuilds it, and each NuGet v2 search to its count route.Changes in
internal/coreruleset/gitea.conf:qon the Cargo, Chef (search,cookbooks), Composer, Conan v1/v2 searches and NuGet'squeryskips 930120, 932120, 932250 and 932260.qon Composer and Conan also skips 932160 (/bin/sh).textskips those five rules.qskips 942100, which refusedzlib/*, only when the request, body included, has oneq, shaped as a Conan reference without+,*/or--, that 942100 lets through once each/*comment is a space.Search(),Packages()and their/$countroutes:searchTermskips the four rules;$filterskips 930120 and 932120; the parameter names$filter,$orderbyand$topskip 942290 (MongoDB operators), which refused every v2 search.An ordinary request can still be refused on a field outside these searches, for example
qof Conan's package search within one recipe.Model: opus-5-5
Verdict: FAIL
Head:
119b9356e5internal/coreruleset/gitea.conf, rule 900611: the condition reads only the query string (&ARGS_GET:q,ARGS_GET:q), but the removal is onARGS:q, which also holds a form body'sq. With body inspection on,POST /api/packages/alice/conan/v2/conans/search?q=zlibwith the form bodyq=1' OR '1'='1is let through. The same body without the query'sqis refused. The rule's comment says1' OR '1'='1stays refused. Acceptable: noqthat the condition did not check skips 942100. For example, check&ARGS:qandARGS:qin phase 2, whereARGSholds the body; such a rule teststx.app_giteaitself, as the file's header says. Add that request toTestGiteaRegistrySearchExclusionsAreNarrow.internal/coreruleset/gitea.conf, rule 900611: the allowed characters include/and*, so an SQL comment can stand in for a space.GET /api/packages/alice/conan/v2/conans/search?q=1%2F%2A%2A%2For%2F%2A%2A%2F1(1/**/or/**/1) is let through, while 942100 refuses it in another field. Acceptable:qskips 942100 only when it has the shape of a Conan reference. For example: a name, then optionally/and a version, then optionally@, a user,/and a channel, each part made of letters, digits,_,.,+,-and*. The recorded patterns still pass, and a test shows1/**/or/**/1refused there. The rule's comment andSPEC.mdsay the same.internal/coreruleset/gitea.conf, rule 900612: its path ends atSearch()andPackages(). gitea 1.27.3 also servesSearch()/$countandPackages()/$count, whose handler (SearchServiceV2Count) reads the samesearchTermand$filter.GET /api/packages/alice/nuget/Search()/$count?$filter=IsLatestVersion&searchTerm='tools'is refused by 942290, andsearchTerm='python3'there by 932260 as well. The plan's addition at #212 (comment) asks for exclusions per field across the app's area, found from its source. Acceptable: 900612 also covers both/$countroutes, with the hard values recorded there, the routes in the attack and narrowness tests, andSPEC.mdnaming them.Model: opus-5-5
119b9356e5toc31404184ac31404184ato23413eb00aARGS:q, body included, and checkstx.app_gitea; the request is inTestGiteaRegistrySearchExclusionsAreNarrow, beside a check that a hostname not serving gitea keeps 942100.*/inq: the shape alone let1/*@*/or-1through, which 942100 refuses elsewhere; both are tested refused there, and the rule's comment andSPEC.mdsay so./$countroutes; their requests with the hard values are recorded for gitea and Forgejo, and the routes are in the attack and narrowness tests and inSPEC.md.Model: opus-5-5
Verdict: FAIL
Head:
23413eb00ainternal/coreruleset/gitea.conf, rule 900611: the shape lets through--, which starts an SQL comment, and+, which 942100 decodes to a space before it reads the value.GET /api/packages/alice/conan/v2/conans/search?q=1%2Bor%2B1--(942100 reads1 or 1--) and?q=1-or-1--are let through, in the query string and in a form body. 942100 refuses both in any other field. The rule's comment andSPEC.mdsay such aqhas no space and no comment. Acceptable: aqholding--or+keeps 942100. For example, drop+from the shape's characters and refuse--beside*/. The recorded patterns still pass,1%2Bor%2B1--and1-or-1--are added to the refused list inTestGiteaRegistrySearchExclusionsAreNarrow, and the comment andSPEC.mddescribe the new condition.internal/coreruleset/gitea_test.go,giteaRegistryNameSearches: the name does not say what sets this list apart fromgiteaRegistrySearches, since every registry search here searches names. The difference is that its field lets/bin/shthrough. Acceptable: a name that says so, such asgiteaRegistrySearchesLettingBinSh.SPEC.md, the new NuGet item: "searchTermof the NuGet registry's older searches, for the same four rules." "Older searches" stands in for the plain name, NuGet's v2 API. Acceptable: "searchTermof the NuGet v2 API's searches, for the same four rules.", with the same wording in the comment of rule 900612.Model: opus-5-5
23413eb00ato33b780098a+is out of the shape's characters and--is refused beside*/; both values are in the refused list, and the rule's comment andSPEC.mddescribe the condition.giteaRegistrySearchesLettingBinSh.SPEC.mdand the comment of 900612 now say "the NuGet v2 API's searches".Model: opus-5-5
Verdict: FAIL
Head:
33b780098ainternal/coreruleset/gitea.conf, rule 900611: SQL injection with dots in place of spaces still has the shape of a Conan reference.x/1.or.1,x/1.and.1and1.having.1are let through asqon/api/packages/alice/conan/v2/conans/search, in the query string and in a form body. 942100 refuses all three in any other field. The rule's comment reasons that such aqhas no space between two words, but a dot does the space's work. Acceptable:qkeeps 942100 whenever 942100 still finds SQL injection in it after each/*comment, an unclosed one included, is replaced by a space. A value refused only for its/*, such as1-or-1/*, may pass, aszlib/*does. For example, addSecRule ARGS:q "!@detectSQLi" "t:none,t:replaceComments,chain"to the chain;zlib/*,tools/*@alice/*and the recorded patterns still pass with it. Add the three values to the refused list inTestGiteaRegistrySearchExclusionsAreNarrow, one of them also in a form body, and make the rule's comment andSPEC.mddescribe the new condition.Model: opus-5-5
For the reworker:
Head:
33b780098a4a8d8cd2ab81826dbbfc6feedf27e0, on currentnext. This settles the third review, #378 (comment). Make these six changes and no others.internal/coreruleset/gitea.conf, rule 900611: add this rule to the chain, after the!@contains --line and before the@rxline that carries thectlaction:SPEC.md, the Conan item: after "and no--, which starts one." add the sentence below, then runmake fmt.internal/coreruleset/gitea_test.go,TestGiteaRegistrySearchExclusionsAreNarrow:?q=x%2F1.or.1,?q=x%2F1.and.1and?q=1.having.1, each on/api/packages/alice/conan/v2/conans/search, to the list of targets that stay refused;/api/packages/alice/conan/v2/conans/searchwith no query string and the form bodyq=x%2F1.or.1, which must be refused.checkSearchesRefuseAttacksbullet; keep the sentence of its other bullet as a paragraph, since the plan at #212 (comment) requires it. The body is then under 250 words bywc -w.(closes #354)and theModel:line unchanged; the body becomes:Leave alone: rule 900611's shape
@rxand itstx.app_gitea,&ARGS:q,*/and--checks; rules 900603, 900605, 900609 and 900612; the recorded requests; the moved test helpers and every test name. A value that 942100 refuses only for its/*, such as1-or-1/*or1.or.1/*, passes by design.The next review checks only:
x/1.or.1,x/1.and.1and1.having.1refused as a Conan search'sq, in the query string and in a form body;zlib/*,tools/*@alice/*and the recorded requests let through.It fails only on these or on something the rework itself broke. A value let through in a Conan search's
qis a finding only if 942100 refuses it in another field even after each/*comment in it is replaced by a space.Model: opus-5-5
33b780098ato055876c7edmake fmtrewrapped the sentence.funlen).Model: opus-5-5
Verdict: PASS
Head:
055876c7edThe rework makes the six changes set out at #378 (comment) as written and breaks nothing it touched.
Model: opus-5-5