EN
  • English
  • Deutsch
  • Polski
  • Italiano
  • Español

Threat model

Warden’s security posture is stated in the open. This page names every threat the daemon is built to resist, the ones it deliberately does not cover, and the switches an operator must turn on to claim the full posture.

Where this comes from
This is the public rendering of the SECURITY.md threat model that ships in the Warden source tree. When the two disagree, the source tree wins.

In-scope threats

Fourteen named classes of risk, each with an independent control rather than one perimeter that has to do everything.

#ThreatControl
1Ad / tracker / malware domain resolutionMulti-format blocklist engine (domain, AdGuard ||domain^, hosts) with per-client profiles, subdomain-walk matching, and CNAME deep inspection
2External list supply-chain attacksSandboxing — external lists cannot use @@ allow rules, $important overrides, or regex; only your own config.toml rules have those powers
3SSRF via list downloadsHardened HTTP client: HTTPS-only on the initial URL and every redirect, literal private / CGNAT / loopback / link-local IPs rejected, body capped at lists.max_body_bytes
4DNS amplification / reflectionResponse Rate Limiting per /24 (v4) or /48 (v6) prefix, plus always-on RFC 8482 ANY-query refusal (a single HINFO answer instead of a multi-KB response)
5Query flooding / per-client abuseAtomic token-bucket rate limiter per client IP (queries_per_second, with a burst allowance for page loads)
6DNS tunneling (data exfiltration)Three per-query heuristics: per-label length, Shannon entropy across labels, and per-domain unique-subdomain rate
7DoH / DoT bypassAnti-bypass module blocks resolution of 40+ known public resolver domains (Google DNS, Cloudflare, Quad9, NextDNS, …) plus operator extra_domains
8Memory DoS (unique-source flooding)Every stateful security module uses a bounded map (100k-entry cap, approximate-LRU eviction) — a flood from unique IPs cannot pin unbounded memory
9Open-resolver misconfigurationFail-closed validator: Warden refuses to boot when it binds 0.0.0.0 / [::] with an empty server.allow_from
10Profile hijacking via IP spoofingMAC enforcement — with server.enforce_device_mac (default on), the resolver cross-checks the ARP table at query time; a mismatch strips the device’s own overrides and re-enters the profile cascade at the subnet level (a matching subnet profile wins, else the default profile, else refused)
11API and IPC brute-forceBearer-token auth with constant-time comparison and per-IP lockout after 10 failures; the IPC socket adds a three-tier ReadOnly / Mutating / Admin gate
12DNS rebindingThe query validator flags labels shaped like four consecutive octets (e.g. 192.168.1.1.evil.com)
13Cache poisoningCache keys include (domain, record_type, dns_class); blocked responses are never cached; entries are weighted to blunt negative-cache flooding
14PID-file race conditionsflock(LOCK_EX|LOCK_NB) on the PID file — the kernel enforces mutual exclusion, so a second instance refuses instead of racing

Out of scope

Named on purpose, so the trade-offs are visible. These belong to a different layer — Warden does not pretend to cover them.

  • ARP spoofing / poisoning — Warden reads the OS ARP table but does not validate it. Use 802.1X, static ARP entries, or a managed switch with port security.
  • IDN homoglyph attacks — domains are matched as ASCII after IDNA encoding; visually similar Unicode (e.g. gооgle.com with a Cyrillic “о”) is a browser / list-curation concern.
  • Shared-user privilege escalation — anyone who can read config.toml or the token file shares admin access. Use OS-level user separation.
  • Encrypted DNS from clients — a client with a hardcoded resolver IP talking its own DoH/DoT cannot be stopped at the DNS layer. Redirect or block outbound 53 / 443 / 853 at the firewall (warden firewall-rules generates the templates).
  • Physical network access — Warden can only filter queries it receives. Use switch-level (802.1X / MAC) port authentication.
  • Compromise of the Warden host — shell access to the machine means all bets are off. Harden the host OS, keep it patched, restrict SSH.

Operator Configuration Contract

Warden filters out of the box. To also resist active abuse, the operator must turn on all eight of these.

RequirementConfigWhy
Set allow_from when binding a non-loopback addressserver.allow_from = ["10.10.1.0/24"]Prevents open-resolver abuse
Generate an API/IPC tokenwarden token generateGates config changes and admin commands
Pin client MACs[[devices]] with mac = "AA:BB:…"Prevents IP-spoofing profile hijack
Keep enforce_device_mac enabledserver.enforce_device_mac = true (default)Cross-checks the ARP table at query time
Block outbound DNS at the firewallwarden firewall-rulesStops clients from bypassing Warden
Use a restrictive default postureleave server.default_profile unset (refuse unknown clients), or set a broadly-denying default profileUnknown clients are refused or filtered, never served openly
Rotate tokens periodicallywarden token regenerateLimits exposure from a leaked token
Keep lists updatedlists.update_interval_secs (default 43200, 12h)Stale lists miss new threats