script/gitea-requests, and the gitea refusals it confirms named in SPEC.md (closes #30)
check / check (push) Canceled after 0s

script/gitea-requests runs gitea 1.27.3 behind the image at its
defaults, sends through it the requests that reading gitea's source
found the Core Rule Set refuses, with a short sample of ordinary use,
and prints each request with the rule ids that matched it. make
gitea-requests runs it; make check does not.

Every case still holds, and each fix would let through what SPEC.md
says stays refused, so the notes specific to gitea now name them with
how each refusal plays out: file names in query parameters that read as
Java, script, PowerShell or SQL, such paths, and an image push that
reuses a layer of an image named like a command.

Model: opus-5-5
This commit was merged in pull request #134.
This commit is contained in:
2026-10-20 13:39:05 +02:00
parent 47aac0235d
commit 60c49a6740
4 changed files with 414 additions and 6 deletions
+52 -4
View File
@@ -1477,8 +1477,47 @@ holds any token file.
Saving such a rule stores it, but the branch settings page gitea then
returns to gets the 403 answer of `smallwebwaf`, so the save looks as
if it failed.
- A file name in a query parameter, those the fourth change leaves out
of 930120, 932160 and 932260 included, in which the Core Rule Set's
rules for Java, script, PowerShell and SQL find what they look for:
`runtime` in OpenJDK's
`src/java.base/share/classes/java/lang/Runtime.java` (944110), a Java
class, as in `java.lang.String.md` (944130), `document.write.js`
(941180), `process.env.d.ts` (934100), `__proto__` (934130), the
PowerShell command `Install-Script`, as in `install-script.sh`
(932120), or a database's name, as in PostgreSQL's
`information_schema.sql` (942140). For such a file, the API's list of
its commits (`path`) is refused, and so are the API's call for the
contents of files that names it in its query (`body`), the commit
graph of that file alone (`file`), and the hidden lines of its diff
(`path`), which stay hidden. A visitor whom gitea sends to sign in on
the way to a page of such a file that needs signing in, such as its
edit page, gets the 403 answer of `smallwebwaf` in place of the
sign-in page (`redirect_to`), and can still sign in by opening the
sign-in page itself.
- A path: a file name ending in `~`, or an `.xhtml` file whose path
holds a space.
- A path that holds what the Core Rule Set takes for a Java class
(944130), as `java.lang.String.md` and
`META-INF/services/org.apache.commons.logging.LogFactory` do, or for
Node.js code (934100), as `process.env.d.ts` does, or that has a
directory named `...` (930100, 930110), such as `.../notes.txt`. The
page of such a file, its raw file, its history, its blame and its edit
page are refused; the directory that holds it lists it, and a clone
carries it.
- A container image push that reuses a layer of an image docker has
pushed to that gitea before, when that image's owner, or its name
after the owner, starts with an entry on the list of commands
(932260), such as `owner/python3-app`, `owner/docker-base` or any
image of an owner named `ansible` or `docker-team`. docker asks gitea
to take the layer from that image, naming it in the query parameter
`from`, which 932260 checks, and gets the 403 answer of `smallwebwaf`.
A docker that keeps its images in containerd's image store, as a new
install of Docker Engine 29 does, then fails the push, and fails each
new try the same way. A docker that keeps them in its own older image
store uploads the layer instead, so the push succeeds after one
refusal for each layer it reuses, and each of those refusals counts
toward the error burst.
- Artifact uploads from `actions/upload-artifact@v3` send the header
`Content-Range`, which the Core Rule Set refuses (920450). The action
sends two files at a time, does not retry a 403 and sends no further file
@@ -1566,10 +1605,19 @@ holds any token file.
- Core Rule Set false positives against real apps (a search for code, and any
body once `SWWAF_WAF_BODY_LIMIT` is set): a match refuses only that request
and bans no one by itself; the request log names the rule, and exclusions by
rule id and path fix it. Further gitea requests the Core Rule Set may refuse
at the defaults, found by reading gitea's source rather than a running gitea,
are collected in https://git.eeqj.de/sneak/smallwebwaf/issues/30 and checked
when milestone 1 runs in front of a real gitea.
rule id and path fix it. `script/gitea-requests` runs gitea behind the image
at the defaults and sends through it a short sample of gitea's ordinary use
and some of the requests that three of the notes specific to gitea say are
refused: for each file the note on a file name in a query parameter names, the
API's list of its commits; for `Runtime.java` alone, the commit graph of that
file, the hidden lines of its diff and the API's call for the contents of
files that names it; the sign-in page gitea sends a visitor to on the way to
the edit page of `document.write.js`; the pages of `java.lang.String.md`,
`META-INF/services/org.apache.commons.logging.LogFactory`, `process.env.d.ts`
and `.../notes.txt`; and one container image push that reuses a layer, which
it does not try again. It reports each request the Core Rule Set refuses, so
that those requests can be checked again when gitea or the Core Rule Set
changes version.
- Attacks carried in request bodies: not refused by default, since on a code
forge bodies are full of code the Core Rule Set takes for attacks. Most of
what shows in URLs and headers is still refused, the client that sends an