# Bans How bans are made, what they cover and how long they last is under "Bans" in [`SPEC.md`](../SPEC.md); the settings are under "How long bans last and what they cover" in [`settings.md`](settings.md). This file says what a ban's notes hold, and how to make, keep or lift a ban. ## The notes Each ban carries notes for deciding whether to lift it, drawn from what `smallwebwaf` already knows. Nothing is looked up to fill them: - the AS number, AS name and country, added when the lookup answers (empty when lookups are off); - what was broken: the rule id and target that matched, or the trap path, or the limit, its window and the count reached; - the client's percentage of the limit, with the setting that gave it; - the reputation sources the client is on; - the request that caused the ban: time, method, host, path with its query string, status and user agent, each text cut to 256 bytes; - the netblock's requests since it was first seen, and how many this ban has refused so far, kept up to date while the ban lasts; - how many earlier bans the netblock had, by cause. ## Managing bans by editing `bans.json` `bans.json` in the state directory holds every ban, indented to be read. A permanent ban's `expires` is `null`. `smallwebwaf` watches the file and takes in an edit as soon as it is saved (see [`state-files.md`](state-files.md)). To ban a netblock, add an entry with its `netblock`, `start` and `expires`. `expires` is `null` for a ban that never ends. `reason`, `notes` and `cause` may be left out; the cause is then `admin`: ```json { "version": 1, "bans": [ { "netblock": "203.0.113.0/24", "start": "2026-10-06T12:00:00Z", "expires": null, "reason": "probes for logins" } ] } ``` To keep a ban `smallwebwaf` made, so that it is never dropped, set its `cause` to `admin`. To lift a ban, add `"lifted"` with the time you lift it, such as `"lifted": "2026-10-06T13:00:00Z"`. The ban then refuses nothing and does not make the netblock's next ban longer. It is kept with its notes. To forget a ban, delete its entry. A ban whose cause is `attack` becomes permanent at the first request it refuses. One whose cause is `admin` or `crowdsec` does not. An edit that cannot be read does not stop the running `smallwebwaf`. It keeps what it holds. At the file's next write it renames your file to `bans.json.bad`, writes the file again from memory, and logs and alerts the error. Mend the `.bad` file and move it back. ## Managing bans through the admin endpoints With `SWWAF_ADMIN_TOKEN` set, and the token in `$TOKEN`: ```sh # Every ban. curl -H "Authorization: Bearer $TOKEN" https://app.example/_smallwebwaf/bans # Ban 203.0.113.0/24 for seven days. curl -H "Authorization: Bearer $TOKEN" \ --json '{"netblock": "203.0.113.0/24", "duration": "7d", "reason": "probes for logins"}' \ https://app.example/_smallwebwaf/bans # Lift the bans on 203.0.113.9. curl -H "Authorization: Bearer $TOKEN" -X DELETE \ https://app.example/_smallwebwaf/bans/203.0.113.9 # What smallwebwaf knows of 203.0.113.9. curl -H "Authorization: Bearer $TOKEN" \ https://app.example/_smallwebwaf/clients/203.0.113.9 ``` See [`admin-endpoints.md`](admin-endpoints.md) for what each answers. An admin whose own address is banned lifts that ban by editing `bans.json`.