sneak, in chat on 6 November, on hearing that the Gitea setup (#187) runs the web attack rules (the OWASP Core Rule Set) in detect-only mode, because at the defaults they refused ordinary Gitea searches and file names:
the web attack rules need to be changed if they flag ordinary gitea traffic as an attack. that’s a false positive.
Definition of done:
In the Gitea setup, the Core Rule Set refuses attacks (SWWAF_WAF_MODE is not detect).
Ordinary Gitea traffic is never refused:
code and issue searches with ordinary words and symbols;
viewing, downloading and editing files with any ordinary file name;
git clone, fetch and push over HTTPS;
API calls with JSON bodies;
the web pages a signed-in user opens.
Each rule that misfires on such a request is switched off as narrowly as it can be: that rule only, on the Gitea paths or fields where it misfires. A one-line comment names the Gitea request it misfired on. A misfire that would hit any site goes in smallwebwaf's default rules; one specific to Gitea goes in the Gitea setup.
A test sends a recorded set of ordinary Gitea requests through, and none is refused. The same test shows a few classic attacks still refused: SQL injection, path traversal, and script injection in a query string.
sneak, in chat on 6 November, on hearing that the Gitea setup (https://git.eeqj.de/sneak/smallwebwaf/pulls/187) runs the web attack rules (the OWASP Core Rule Set) in detect-only mode, because at the defaults they refused ordinary Gitea searches and file names:
> the web attack rules need to be changed if they flag ordinary gitea traffic as an attack. that’s a false positive.
**Definition of done:**
- In the Gitea setup, the Core Rule Set refuses attacks (`SWWAF_WAF_MODE` is not `detect`).
- Ordinary Gitea traffic is never refused:
- code and issue searches with ordinary words and symbols;
- viewing, downloading and editing files with any ordinary file name;
- git clone, fetch and push over HTTPS;
- API calls with JSON bodies;
- the web pages a signed-in user opens.
- Each rule that misfires on such a request is switched off as narrowly as it can be: that rule only, on the Gitea paths or fields where it misfires. A one-line comment names the Gitea request it misfired on. A misfire that would hit any site goes in smallwebwaf's default rules; one specific to Gitea goes in the Gitea setup.
- A test sends a recorded set of ordinary Gitea requests through, and none is refused. The same test shows a few classic attacks still refused: SQL injection, path traversal, and script injection in a query string.
- `make check` passes.
This builds on https://git.eeqj.de/sneak/smallwebwaf/pulls/187 once it lands.
Model: opus-5-5
clawbot
self-assigned this 2026-11-06 18:53:55 +01:00
Plan for the implementer. Start from next once #187 has landed. docs/gitea.md, section "What the Core Rule Set refuses in block mode", lists every misfire found so far, with the rule ids; make gitea-requests reproduces them.
Misfires any site would hit (a query string that reads as an attack, a file or branch name that starts with a command name, a file name in a query parameter, a container layer reused): add a narrow exclusion to internal/waf's directives, beside smallwebwaf's existing changes to the Core Rule Set: SecRuleUpdateTargetById for that rule and that field, or a ctl exclusion limited to the path pattern. Each gets a one-line comment naming the request it misfired on. SPEC.md's "Attack detection" list of changes says what each one does.
Misfires only Gitea's own paths cause: a new servewaf setting, SWWAF_WAF_EXCLUSIONS_FILE, default empty: a file of Core Rule Set exclusions, in the same rule language, loaded after smallwebwaf's own directives. A file that cannot be read or does not parse fails startup. Rules in it may not use ids from 900000 to 900999. The Gitea setup ships deploy/gitea/crs-exclusions.conf, mounted read-only into servewaf, each exclusion limited to the Gitea path where it misfires, with its one-line comment. Package: internal/config parses the setting; internal/waf loads the file.
The setup: remove SWWAF_WAF_MODE: detect from deploy/gitea/compose.yaml, so it runs at the default, block.
The test:script/gitea-setup sends the ordinary requests script/gitea-requests sends (searches, file pages and downloads, edits, clone, fetch, push, API calls with JSON bodies, signed-in pages) and fails if any is refused. It also sends three attacks in a query string, SQL injection, path traversal and script injection, and fails unless each is refused.
Docs:docs/gitea.md's section on what the Core Rule Set refuses becomes a short section on the exclusions: where they live and how to add one. The README settings table and docs/settings.md list the new setting.
make check and make gitea-setup pass.
Disclosure for the PR body: the list of ordinary requests is what the test sends; a request outside it may still misfire, and goes in the exclusions file when found.
Model: opus-5-5
Plan for the implementer. Start from `next` once https://git.eeqj.de/sneak/smallwebwaf/pulls/187 has landed. `docs/gitea.md`, section "What the Core Rule Set refuses in `block` mode", lists every misfire found so far, with the rule ids; `make gitea-requests` reproduces them.
- **Misfires any site would hit** (a query string that reads as an attack, a file or branch name that starts with a command name, a file name in a query parameter, a container layer reused): add a narrow exclusion to `internal/waf`'s directives, beside smallwebwaf's existing changes to the Core Rule Set: `SecRuleUpdateTargetById` for that rule and that field, or a `ctl` exclusion limited to the path pattern. Each gets a one-line comment naming the request it misfired on. `SPEC.md`'s "Attack detection" list of changes says what each one does.
- **Misfires only Gitea's own paths cause:** a new servewaf setting, `SWWAF_WAF_EXCLUSIONS_FILE`, default empty: a file of Core Rule Set exclusions, in the same rule language, loaded after smallwebwaf's own directives. A file that cannot be read or does not parse fails startup. Rules in it may not use ids from 900000 to 900999. The Gitea setup ships `deploy/gitea/crs-exclusions.conf`, mounted read-only into `servewaf`, each exclusion limited to the Gitea path where it misfires, with its one-line comment. Package: `internal/config` parses the setting; `internal/waf` loads the file.
- **The setup:** remove `SWWAF_WAF_MODE: detect` from `deploy/gitea/compose.yaml`, so it runs at the default, `block`.
- **The test:** `script/gitea-setup` sends the ordinary requests `script/gitea-requests` sends (searches, file pages and downloads, edits, clone, fetch, push, API calls with JSON bodies, signed-in pages) and fails if any is refused. It also sends three attacks in a query string, SQL injection, path traversal and script injection, and fails unless each is refused.
- **Docs:** `docs/gitea.md`'s section on what the Core Rule Set refuses becomes a short section on the exclusions: where they live and how to add one. The README settings table and `docs/settings.md` list the new setting.
- `make check` and `make gitea-setup` pass.
Disclosure for the PR body: the list of ordinary requests is what the test sends; a request outside it may still misfire, and goes in the exclusions file when found.
Model: opus-5-5
Correction to the plan above, from the naming audit (#192 (comment)): the new setting is SWWAF_CORE_RULE_SET_EXCLUSIONS_FILE, not SWWAF_WAF_EXCLUSIONS_FILE. The other SWWAF_WAF_ settings keep their names in this unit; the audit's rename unit changes them later. Everything else in the plan stands.
Model: opus-5-5
Correction to the plan above, from the naming audit (https://git.eeqj.de/sneak/smallwebwaf/issues/192#issuecomment-169850): the new setting is `SWWAF_CORE_RULE_SET_EXCLUSIONS_FILE`, not `SWWAF_WAF_EXCLUSIONS_FILE`. The other `SWWAF_WAF_` settings keep their names in this unit; the audit's rename unit changes them later. Everything else in the plan stands.
Model: opus-5-5
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.
sneak, in chat on 6 November, on hearing that the Gitea setup (#187) runs the web attack rules (the OWASP Core Rule Set) in detect-only mode, because at the defaults they refused ordinary Gitea searches and file names:
Definition of done:
SWWAF_WAF_MODEis notdetect).make checkpasses.This builds on #187 once it lands.
Model: opus-5-5
Plan for the implementer. Start from
nextonce #187 has landed.docs/gitea.md, section "What the Core Rule Set refuses inblockmode", lists every misfire found so far, with the rule ids;make gitea-requestsreproduces them.internal/waf's directives, beside smallwebwaf's existing changes to the Core Rule Set:SecRuleUpdateTargetByIdfor that rule and that field, or actlexclusion limited to the path pattern. Each gets a one-line comment naming the request it misfired on.SPEC.md's "Attack detection" list of changes says what each one does.SWWAF_WAF_EXCLUSIONS_FILE, default empty: a file of Core Rule Set exclusions, in the same rule language, loaded after smallwebwaf's own directives. A file that cannot be read or does not parse fails startup. Rules in it may not use ids from 900000 to 900999. The Gitea setup shipsdeploy/gitea/crs-exclusions.conf, mounted read-only intoservewaf, each exclusion limited to the Gitea path where it misfires, with its one-line comment. Package:internal/configparses the setting;internal/wafloads the file.SWWAF_WAF_MODE: detectfromdeploy/gitea/compose.yaml, so it runs at the default,block.script/gitea-setupsends the ordinary requestsscript/gitea-requestssends (searches, file pages and downloads, edits, clone, fetch, push, API calls with JSON bodies, signed-in pages) and fails if any is refused. It also sends three attacks in a query string, SQL injection, path traversal and script injection, and fails unless each is refused.docs/gitea.md's section on what the Core Rule Set refuses becomes a short section on the exclusions: where they live and how to add one. The README settings table anddocs/settings.mdlist the new setting.make checkandmake gitea-setuppass.Disclosure for the PR body: the list of ordinary requests is what the test sends; a request outside it may still misfire, and goes in the exclusions file when found.
Model: opus-5-5
Correction to the plan above, from the naming audit (#192 (comment)): the new setting is
SWWAF_CORE_RULE_SET_EXCLUSIONS_FILE, notSWWAF_WAF_EXCLUSIONS_FILE. The otherSWWAF_WAF_settings keep their names in this unit; the audit's rename unit changes them later. Everything else in the plan stands.Model: opus-5-5