SPEC: parameter change for every app, gitea name refusals, v3 uploads (closes #6)

Fifth review of the spec update:

- The change that leaves gitea's path and branch parameters out of
  930120, 932160 and 932260 says it holds in front of every app, that
  commands and file URLs pass there too, and that no setting restores
  the rules; Risks names an app that uses one of them as a server file
  or in a shell.
- The gitea notes no longer claim that any branch or file name passes:
  they name `refSubUrl`, `name`, `tag`, `template` and `rule_name`,
  which keep the rules, and what each refusal looks like.
- `actions/upload-artifact@v3` is refused once or twice per upload and
  the step fails; only more than 30 refusals a minute ban the runner.

Model: opus-5-5
This commit is contained in:
2026-09-28 21:04:34 +00:00
parent 44a95a6396
commit 8b3aba84b2
+74 -36
View File
@@ -538,9 +538,9 @@ The settings, by group:
- `WAF_PARANOIA_LEVEL` (default `1`), `WAF_ANOMALY_THRESHOLD` (default `5`): - `WAF_PARANOIA_LEVEL` (default `1`), `WAF_ANOMALY_THRESHOLD` (default `5`):
the Core Rule Set's own two tuning values, at the Core Rule Set's own the Core Rule Set's own two tuning values, at the Core Rule Set's own
defaults. defaults.
- The sidecar also changes the Core Rule Set 4.25.0 in five ways that no - The sidecar also changes the Core Rule Set 4.25.0 in five ways, since in
setting undoes, since in front of gitea each would otherwise refuse front of gitea it would otherwise refuse ordinary requests. The changes
ordinary requests: hold in front of every app, and no setting undoes them:
- PUT, PATCH and DELETE are allowed methods besides GET, HEAD, POST and - PUT, PATCH and DELETE are allowed methods besides GET, HEAD, POST and
OPTIONS; APIs, container image pushes and package uploads use them. OPTIONS; APIs, container image pushes and package uploads use them.
Other methods stay refused. Other methods stay refused.
@@ -566,11 +566,18 @@ The settings, by group:
such as `.gitignore`, `package.json`, `docker-compose.yml`, such as `.gitignore`, `package.json`, `docker-compose.yml`,
`bin/docker-entrypoint` or a branch named `docker-build`, and gitea `bin/docker-entrypoint` or a branch named `docker-build`, and gitea
reads these values as names within a repository or its own records, or reads these values as names within a repository or its own records, or
as a page of its own site. What only these three rules refuse, such as as a page of its own site. Like the other changes, this one holds in
`/etc/passwd` or `whoami` on its own, is therefore let through in front of every app, not only gitea, and no setting restores the three
those parameters; path traversal (`../`), SQL and script injection and rules in those parameters. What only these three rules refuse is let
PHP, Java and Node.js code are still refused there, and every other through there, and that is more than a name such as `/etc/passwd` or
parameter and cookie keeps all three rules. `whoami` on its own: commands such as `|cat /etc/passwd`,
`wget http://…` and `nc -e /bin/sh …`, and `file:///etc/passwd`, pass
as well. Path traversal (`../`), SQL and script injection and PHP,
Java and Node.js code are still refused there, and every other
parameter and cookie keeps all three rules. An app that uses one of
these parameters as a file on the server, or passes it to a shell,
gets no help from the three rules there (see "Risks the design has to
handle").
- Responses are not inspected. A raw file from a repository, such as a - Responses are not inspected. A raw file from a repository, such as a
shell script, looks to the response rules like source code leaking shell script, looks to the response rules like source code leaking
from the server. from the server.
@@ -1136,36 +1143,59 @@ networks:
`UPSTREAM_REQUEST_TIMEOUT` raised to fit. The Core Rule Set does not read `UPSTREAM_REQUEST_TIMEOUT` raised to fit. The Core Rule Set does not read
an upload's body, which streams through without being held in memory. an upload's body, which streams through without being held in memory.
- At the defaults (see "Configuration surface", attack detection), the Core - At the defaults (see "Configuration surface", attack detection), the Core
Rule Set lets gitea's ordinary use through, whatever its files and Rule Set lets gitea's ordinary use through, apart from the refusals in the
branches are called: browsing and views of files in a repository, with next note: browsing and views of files in a repository, with their
their history, blame and the file tree; diffs, including their hidden history, blame and the file tree; diffs, including their hidden lines and
lines and large files, and pull request review; git's clone, fetch and large files, and pull request review; git's clone, fetch and push over
push over HTTP; signing in, including the return to the page a visitor HTTP; signing in, including the return to the page a visitor came from and
came from and sign-in with Git Credential Manager, git-credential-oauth or sign-in with Git Credential Manager, git-credential-oauth or tea; the
tea; the API's calls for a file and its commits; pushing and pulling API's calls for a file and its commits; pushing and pulling container
container images and packages; Actions runners, and artifacts uploaded images and packages; Actions runners, and artifacts uploaded with
with `actions/upload-artifact@v4`; and posting issues, pull requests, `actions/upload-artifact@v4`; and posting issues, pull requests, comments,
comments, wiki pages and files saved in the web editor, code included, wiki pages and files saved in the web editor, code included, since no body
since no body is read. It can still refuse a query string that reads to it is read.
as an attack, most often a search: one for a name on its lists of system - The Core Rule Set can still refuse the requests below. Each refusal
files and commands, such as `package.json`, `.gitignore` or answers only that request, with 403, and bans no one by itself: it counts
`docker-compose.yml`, or for text that starts with a command name, such as toward the error burst, which a person does not reach this way. The
`python3` or `ssh key`; or one holding a shell command with its options or request log names the rule in `waf_rule_ids`, which `WAF_DISABLED_RULES`
a system path (`ls -la`, `sed -i`, `/bin/sh`), a command in backticks, can switch off.
script code (`fetch(`, `${VAR}`, `process.env`), HTML (`<img src=`), an - A query string that reads to it as an attack, most often a search: one
SQL statement (`SELECT * FROM users WHERE`), or a URL naming an IP address for a name on its lists of system files and commands, such as
or `localhost`. The lists refuse such a name in any other query parameter `package.json`, `.gitignore` or `docker-compose.yml`, or for text that
starts with a command name, such as `python3` or `ssh key`; or one
holding a shell command with its options or a system path (`ls -la`,
`sed -i`, `/bin/sh`), a command in backticks, script code (`fetch(`,
`${VAR}`, `process.env`), HTML (`<img src=`), an SQL statement
(`SELECT * FROM users WHERE`), or a URL naming an IP address or
`localhost`. The lists refuse such a name in any other query parameter
too, such as a release attachment uploaded through the API as too, such as a release attachment uploaded through the API as
`docker-compose.yml`. A path can be refused as well: a file name ending in `docker-compose.yml`.
`~`, or an `.xhtml` file whose path holds a space. Such a refusal answers - A branch, tag or file name that starts with `docker-`, `python3`,
only that request, with 403, and bans no one by itself: it counts toward `ansible`, `base64`, `whoami` or another entry on the Core Rule Set's
the error burst, which a person searching does not reach. The request log list of commands (932260), where gitea's own pages send it in a query
names the rule in `waf_rule_ids`, which `WAF_DISABLED_RULES` can switch parameter that 930120, 932160 and 932260 still check: `refSubUrl`, the
off. branch or tag of a directory listing, sent when the listing asks for
its entries' last commits in a second request, as it does whenever
gitea takes more than a second to work them out; `name`, when a branch
is deleted or restored on the branches page; `tag`, when a release is
started from a tag; `template`, the file of an issue template, when an
issue is opened from it; and `rule_name`, when a branch protection
rule is opened for editing in the repository's settings. For a branch
named `docker-build`, a directory listing that makes that second
request leaves those last commits out and shows an error, and the
branches page shows an error instead of deleting or restoring the
branch. A release started from such a tag, an issue from such a
template or such a rule opened for editing gets the sidecar's 403
answer in place of its form.
- A path: a file name ending in `~`, or an `.xhtml` file whose path
holds a space.
- Artifact uploads from `actions/upload-artifact@v3` send the header - Artifact uploads from `actions/upload-artifact@v3` send the header
`Content-Range`, which the Core Rule Set refuses (920450). Each file of `Content-Range`, which the Core Rule Set refuses (920450). The action
the artifact is refused with 403 and the step fails; an artifact of more sends two files at a time, does not retry a 403 and sends no further file
than 30 files also bans the runner through the error burst. once one is refused, so an upload is refused once or twice, however many
files it holds, and the step fails. One upload does not ban the runner;
more than 30 such refusals from its address within a minute, as when many
jobs upload at once, ban it through the error burst.
`actions/upload-artifact@v4` does not send the header. `actions/upload-artifact@v4` does not send the header.
- An Actions runner that reaches gitea through the sidecar sends requests - An Actions runner that reaches gitea through the sidecar sends requests
all day. One older than version 0.4 (April 2026) asks for work every 2 all day. One older than version 0.4 (April 2026) asks for work every 2
@@ -1248,6 +1278,14 @@ networks:
attack is still subject to the rule files, the limits and the bans, and attack is still subject to the rule files, the limits and the bans, and
`WAF_BODY_LIMIT` switches body inspection on for apps whose forms carry no `WAF_BODY_LIMIT` switches body inspection on for apps whose forms carry no
code. code.
- An app that uses `path`, `ref` or another of the query parameters left out of
930120, 932160 and 932260 (see "Configuration surface", attack detection) as a
file on the server, or passes it to a shell: that change holds in front of
every app and no setting restores the three rules, so what only they refuse
reaches the app in those parameters, such as `/etc/passwd`, `|cat /etc/passwd`
or `nc -e /bin/sh …`. Path traversal (`../`) is still refused there. Such an
app has to check those values itself, or refuse what it must never receive in
them with a rule file.
- The admin endpoints can be reached from the internet: all but the health check - The admin endpoints can be reached from the internet: all but the health check
need a token and are off while it is unset, and a missing or wrong token need a token and are off while it is unset, and a missing or wrong token
counts toward the error burst, so a client guessing tokens is soon banned. counts toward the error burst, so a client guessing tokens is soon banned.