SPEC: gitea cookies and Referer kept from false refusals (closes #6)

Seventh review of the spec update:

- The Core Rule Set now reads requests without the `gitea_flash` and
  `redirect_to` cookies. A refusal there kept a browser out of the
  whole site, and not only 930120, 932160 and 932260 refuse ordinary
  names in them: the Java, script, PowerShell and database-name rules
  do too. Risks names an app that reads either cookie.
- `Referer` is left out of 932340 and 944110, which refused every
  request made from the results of a one-word search such as `env`,
  and from OpenJDK's `java.base` pages that name `Runtime`.
- The search note covers text whose first word has a listed command
  right after a `/`.

Model: opus-5-5
This commit is contained in:
2026-09-28 22:28:53 +00:00
parent 22f32a46ab
commit 7b48306203
+53 -23
View File
@@ -538,7 +538,7 @@ The settings, by group:
- `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
defaults.
- The sidecar also changes the Core Rule Set 4.25.0 in five ways, since in
- The sidecar also changes the Core Rule Set 4.25.0 in six ways, since in
front of gitea it would otherwise refuse ordinary requests. The changes
hold in front of every app, and no setting undoes them:
- PUT, PATCH and DELETE are allowed methods besides GET, HEAD, POST and
@@ -559,25 +559,50 @@ The settings, by group:
- The query parameters in which gitea sends file paths, branch and
workflow names and the page to return to after signing in (`path`,
`files`, `skip-to`, `sub_path`, `ref`, `sha`, `branch`, `workflow`,
`artifactName` and `redirect_to`), and the `redirect_to` cookie, are
not checked against the Core Rule Set's lists of system files
(930120), shell paths (932160) and command names (932260). In a
repository any name on those lists can be an ordinary file or branch,
such as `.gitignore`, `package.json`, `docker-compose.yml`,
`bin/docker-entrypoint` or a branch named `docker-build`, and gitea
reads these values as names within a repository or its own records, or
as a page of its own site. Like the other changes, this one holds in
front of every app, not only gitea, and no setting restores the three
rules in those parameters. What only these three rules refuse is let
through there, and that is more than a name such as `/etc/passwd` or
`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").
`artifactName` and `redirect_to`) are not checked against the Core
Rule Set's lists of system files (930120), shell paths (932160) and
command names (932260). In a repository any name on those lists can be
an ordinary file or branch, such as `.gitignore`, `package.json`,
`docker-compose.yml`, `bin/docker-entrypoint` or a branch named
`docker-build`, and gitea reads these values as names within a
repository or its own records, or as a page of its own site. Like the
other changes, this one holds in front of every app, not only gitea,
and no setting restores the three rules in those parameters. What only
these three rules refuse is let through there, and that is more than a
name such as `/etc/passwd` or `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 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").
- The Core Rule Set reads the request without the `gitea_flash` and
`redirect_to` cookies, and does not check `Referer` for a Unix command
given without arguments (932340) or for Java starting a process
(944110). Gitea writes into `gitea_flash` a message for the next page
naming what was just done, such as a file deleted in the web editor or
a branch, milestone or project created, and into `redirect_to` the
page to return to after signing in, often the one the visitor clicked
"Sign in" on; `Referer` is the address of the page a request comes
from. In these cookies the Core Rule Set takes names such as
`package.json`, `document.write.js` or `Get-ChildItem.ps1`, and titles
that hold them, for attacks. In `Referer` it takes the address of a
search for one word, such as `env`, `set` or `last`, when the address
ends in it, and the address of OpenJDK's
`src/java.base/share/classes/java/lang/Runtime.java`, which holds both
`runtime` and `java.`. A browser sends such a cookie with every
request until gitea replaces or removes it, which gitea cannot do
while the sidecar refuses those requests, so one refusal would keep
the browser out of the whole site. A browser names a page in `Referer`
on everything the page loads and on every link followed from it, so
all of those would be refused. Gitea shows the message with any script
removed and returns only to a page of its own site. Like the other
changes, this one holds in front of every app: an attack sent in a
cookie of either name is not refused by the Core Rule Set, nor is a
Unix command without arguments or Java starting a process sent in
`Referer`. Every other cookie is read in full, and `Referer` keeps the
other rules, script and SQL injection among them.
- Responses are not inspected. A raw file from a repository, such as a
shell script, looks to the response rules like source code leaking
from the server.
@@ -1153,7 +1178,9 @@ networks:
images and packages; Actions runners, and artifacts uploaded with
`actions/upload-artifact@v4`; and posting issues, pull requests, comments,
wiki pages and files saved in the web editor, code included, since no body
is read.
is read, and the page gitea shows after a change with its message naming
what was done, such as a file deleted or a branch, milestone or project
created.
- The Core Rule Set can still refuse the requests below. Each refusal
answers only that request, with 403, and bans no one by itself: it counts
toward the error burst, which a person does not reach this way. The
@@ -1162,7 +1189,8 @@ networks:
- A query string that reads to it as an attack, most often a search: one
for a name on its lists of system files and commands, such as
`package.json`, `.gitignore` or `docker-compose.yml`, or for text that
starts with a command name, such as `python3` or `ssh key`; or one
starts with a command name, or whose first word has one right after a
`/`, such as `python3`, `ssh key` or `feat/docker-support`; 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
@@ -1289,7 +1317,9 @@ networks:
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.
them with a rule file. So does an app that reads a cookie named `gitea_flash`
or `redirect_to`, which the Core Rule Set does not read, or passes `Referer`
to a shell.
- 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
counts toward the error burst, so a client guessing tokens is soon banned.