# smallwebwaf in front of gitea These notes record what `smallwebwaf` does in front of gitea at the default settings. They are observations, not requirements; the requirements are in [`SPEC.md`](../SPEC.md). `script/gitea-requests` runs gitea behind the image and sends through it a sample of gitea's ordinary use and the requests named below. It reports each request the Core Rule Set refuses, so that these notes can be checked again when gitea or the Core Rule Set changes version. ## What the defaults cover - SSH access to gitea does not pass through `smallwebwaf` and is not protected by it. - A clone is a response. It fits the defaults of 30 minutes and 5 GiB for all but the largest repositories and slowest links. - A push is a request, and so is every other upload: - a git push; - an LFS object; - a container image layer; - a package file; - a release attachment. At the defaults, an upload larger than 100 MiB or taking more than 60 seconds is cut off, and no one is banned for it. "Size and time limits" in `SPEC.md` gives the answers the client gets. A gitea that takes large uploads needs `SWWAF_REQUEST_MAX_BYTES`, `SWWAF_CLIENT_REQUEST_TIMEOUT` and `SWWAF_UPSTREAM_REQUEST_TIMEOUT` raised to fit. - Archive download and blame or history pages are what scrapers hammer. The request limits do most of the work there. - An Actions runner that reaches gitea through `smallwebwaf` sends requests all day. One older than version 0.4 (April 2026) asks for work every 2 seconds, 43,200 requests a day, and reports a running job's log and state every second. So it passes the day limit of 50,000 after about an hour and a quarter of jobs. It is then banned, the job it is running fails, and each repeat within a day makes the ban longer. Newer runners ask less often, but a busy one, or several on one address, can still pass it. Put the runners' addresses in `SWWAF_RATE_LIMIT_EXEMPT_NETS`. ## What the Core Rule Set lets through At the defaults, the Core Rule Set lets gitea's ordinary use through, apart from the refusals in the next section: - browsing and views of files in a repository, with their history, blame and the file tree; - diffs, including their hidden lines and large files, and pull request review; - git's clone, fetch and push over HTTP; - signing in, including the return to the page a visitor came from, and sign-in with Git Credential Manager, git-credential-oauth or tea; - the API's calls for a file and its commits; - pushing and pulling container images and packages; - Actions runners, and artifacts uploaded with `actions/upload-artifact@v4`; - posting issues, pull requests, comments, wiki pages and files saved in the web editor, code included, since no body is read; - the page gitea shows after a change, with its message naming what was done. ## What the Core Rule Set still refuses Each refusal answers only that request ("Bans" in `SPEC.md` says what it counts toward). The request log names the rule in `waf_rule_ids`, which `SWWAF_WAF_DISABLED_RULES` can switch off. ### A query string that reads as an attack Most often this is a search. Every query parameter is checked against the Core Rule Set's lists of system files and commands, except the ten named under "Attack detection" in `SPEC.md`. A release attachment uploaded through the API as `docker-compose.yml` is refused the same way. Examples: - a name on those lists, such as `package.json`, `.gitignore` or `docker-compose.yml`; - text that starts with a command name, or whose first word has one right after a `/`, such as `python3`, `ssh key` or `feat/docker-support`; - a shell command with its options or a system path (`ls -la`, `sed -i`, `/bin/sh`), or a command in backticks; - script code (`fetch(`, `${VAR}`, `process.env`), HTML (`