Files
smallwebwaf/docs/rules.md
T
sneak 1dbe17e594
check / check (push) Waiting to run
README rewritten from scratch so a newcomer can follow it (closes #154, closes #155)
The old README opened with project history and one list of a hundred
settings. The new one leads with what smallwebwaf is, what it protects
against, how to build and deploy it, what happens to a request, the
settings most deployments touch, how to check it works, the entrypoints,
the rationale and the design, as REPO_POLICIES.md requires. The reference
lists, every setting, the rule file format, the endpoints, the request
log's fields, the alert events, the metrics, the state files, the image
and the gitea notes, move to files under docs/, each linked from the
README, with SPEC.md as the one place for behaviour. Every statement was
checked against the code on next.

Model: fable-5-1
2026-10-22 22:29:53 +00:00

2.7 KiB

Rule files

The format of a rule file, and the default file the image ships. "Rule files" in SPEC.md says how the files are read, watched and mounted, and what each action leads to.

The format

A rule is a line of four fields separated by spaces or tabs: an id, a target, an action and a regex. The regex runs to the end of the line. Blank lines and lines starting with # are ignored.

# id           target      action  regex
env-file       path        ban     (?i)^/\.env(\.[a-z]+)?$
scanner-agent  user_agent  ban     (?i)\b(sqlmap|nikto|nuclei|wpscan)\b
  • The id is letters, digits, - and _, unique across all files. The log line, the metrics, the alerts and a ban's notes name the rule by it.
  • The target is what the regex is matched against:
    • path: the path without the query;
    • uri: the path and the query together;
    • query: the query as sent;
    • method, host, user_agent and referer;
    • header:<Name>: any one request header but Host and Transfer-Encoding.
  • The action is log, block or ban.
  • The regex is in Go's syntax, RE2. It matches anywhere in the target unless anchored with ^ and $. (?i) at its front makes it ignore case.

The default file

The image ships one file, share/rules.d/00-default.rules, installed as /etc/smallwebwaf/rules.d/00-default.rules:

# 00-default.rules: probes no real visitor sends, anchored at the site root

# id             target      action  regex
env-file         path        ban     (?i)^/\.env(\.[a-z]+)?$
vcs-dir          path        ban     (?i)^/\.(git|svn|hg|bzr)(/|$)
secrets-dir      path        ban     (?i)^/\.(aws|ssh|docker|kube)/
secret-file      path        ban     (?i)^/\.(htpasswd|htaccess|npmrc|netrc|pgpass|git-credentials|bash_history|DS_Store)$
editor-dir       path        ban     (?i)^/\.(vscode|idea)/
backup-file      path        ban     (?i)^/[^/]+\.(php(\.[a-z0-9]+|~)|sql(\.[a-z0-9]+)?)$
log-file         path        ban     (?i)^/(debug|error|access)\.log$
compose-file     path        ban     (?i)^/(docker-)?compose\.ya?ml$
php-shell        path        ban     (?i)^/(shell|c99|r57|wso|alfa)\.php$
scanner-agent    user_agent  ban     (?i)\b(sqlmap|nikto|nuclei|masscan|zgrab|wpscan)\b
path-traversal   uri         block   (\.\./){2,}
empty-agent      user_agent  log     ^$

A file of your own

An app's Dockerfile adds rules of its own in a file named to sort after the default, such as 50-gitea.rules:

# 50-gitea.rules: WordPress probes, which gitea never serves
wp-probe         path        ban     (?i)^/(wp-login\.php|xmlrpc\.php|wp-admin/)
COPY 50-gitea.rules /etc/smallwebwaf/rules.d/50-gitea.rules