vaultwarden-crs-plugin
A drop-in OWASP CRS 4.0+ plugin that makes the Core Rule Set play nicely with Vaultwarden — the Rust, Bitwarden-compatible server — and optionally locks the host down to Vaultwarden’s known route map.
→ GitHub · Self-hosted Vaultwarden guide · All CRS plugins
Why Vaultwarden needs a different approach
Vaultwarden is a JSON API: the web vault, browser extensions, mobile, desktop and the Bitwarden CLI all POST application/json bodies whose argument names are JSON keys that vary per endpoint and per client version. A vimbadmin-style ARGS_NAMES allowlist would false-block real clients, so this plugin deliberately ships no arg-name allowlist for JSON bodies. Its positive-security layer is a path allowlist only. Bodies are end-to-end encrypted (EncString 2.<iv>|<ct>|<mac> blobs + base64), so the before-rules strip the known-noisy base64/SQLi/PHP target families on the encrypted write paths rather than weakening the whole engine.
What it does
- False-positive exclusions (
vaultwarden-before.conf) — surgical, host-scoped exclusions so legitimate inputs don’t trip CRS: the Argon2 admintoken, the OAuth password-grant hashes on/identity/connect/token, the EncString cipher/account/send blobs under/api, and user-supplied icon domains. - Positive security / path allowlist (
vaultwarden-after.conf, opt-in) — allow Vaultwarden’s real mount points (/api,/identity,/admin,/events,/icons,/notifications,/attachments, static routes and the web-vault tree), deny everything else. Stops/.env//wp-login.phpscanner noise before it reaches the backend. The route map is derived from Vaultwarden’s source (src/api/mod.rs+src/api/web.rs), not guessed.
Hardening since 1.1.0
The positive-security layer also enforces an HTTP-method allowlist (only GET/POST/PUT/DELETE/HEAD/OPTIONS; TRACE/CONNECT/PATCH/junk verbs denied), requires application/json on /api writes (except multipart sends and attachment uploads), anchors static-file extensions to known prefixes so a deep fake path like /x/y/z.json no longer slips through, and feeds the CRS inbound anomaly score on every block so fail2ban / CRS DoS layers see the probe.
Optional arg-name allowlist (1.2.0, experimental)
JSON bodies are never name-allowlisted, but the two non-JSON surfaces are stable and fully enumerable, so 1.2.0 adds an optional, separately-gated allowlist for them: the /identity/connect/token form fields (fixed by the ConnectData struct) and GET query-string parameter names. These live in before.conf so they evaluate before CRS’s anomaly-blocking rule. Enable only after a DetectionOnly burn-in.
Install & enable
Copy the three files (vaultwarden-config.conf, vaultwarden-before.conf, vaultwarden-after.conf) into your CRS plugins/ directory. The plugin is OFF by default — it weakens CRS on Vaultwarden’s routes, so enable it per vhost only, never globally:
server {
server_name vault.example.com;
modsecurity on;
modsecurity_rules '
SecAction "id:9530001,phase:1,nolog,pass,setvar:tx.vaultwarden-plugin_enabled=1"
';
}
On Apache/mod_security2, set the same variable in the matching <Location>/<VirtualHost>. Roll the path allowlist out in CRS DetectionOnly first, then flip to blocking. Requires CRS 4.0+ on any ModSecurity-compatible WAF.