IP reputation / dynamic denylist feed
As of 0.37.0 DaloyJS ships ipReputation(). Where ipRestriction() enforces a static allow/deny list compiled once at startup, ipReputation() wires pluggable, periodically-refreshed abuse feeds — Tor exit lists, Spamhaus DROP, cloud-abuse ranges, or your own threat intelligence — into the request path without a redeploy.
- Pluggable feeds — any source that yields IP / CIDR strings.
urlFeed()ships for the common case (fetch a newline / Spamhaus-DROP-style list over HTTP). - Periodic refresh — the denylist reloads on an
unref'd timer so stale ranges expire and new ones are picked up automatically. - Fail-open— a denylist is additive defense, never the only gate. If a feed can't be loaded (initial or refresh), traffic is not blocked: the last-known-good list is retained. A feed outage never takes your app down.
It reuses the same SSRF-grade CIDR matcher as ipRestriction(), is dependency-free, and runs on every supported runtime.
Quick start
Wiring abuse feeds
A feed is anything implementing IpReputationFeed:
urlFeed() covers the common case. It fetches the URL, understands the Spamhaus-DROP-style <cidr> ; <annotation> format, and skips #, ;, and // comment lines. Lines that aren't valid IPs/CIDRs are skipped, so a partially-malformed feed still loads its good rows.
Fail-open semantics
Reputation is layered defense, so an unavailable feed must never block legitimate traffic:
- A failed initial load leaves an empty (permissive) denylist — requests flow.
- A failed refresh keeps the previous, last-known-good entries for that feed; the other feeds are unaffected.
- An unresolvable client IP is treated as not-listed.
Observe feed health with onError:
Monitor mode
Roll a new feed out in "log" mode first to measure what it would block before you enforce it:
Manual refresh & introspection
ipReputation() returns a controller you can drive directly:
Custom IP resolution
By default the client IP is resolved from the socket-supplied value; set trustProxyHeaders: true to read X-Forwarded-For / X-Real-IP (only behind a proxy you trust to overwrite them), or pass your own resolveIp:
Security notes
- Defense in depth. A denylist complements — never replaces — authentication, rate limiting, and
ipRestriction()allowlists. - Trust your feeds. A compromised feed can deny legitimate clients. Prefer reputable sources and watch
onError/ match volume. - SSRF.
urlFeed()uses the platformfetch; pass an SSRF-guardedfetchImplif feed URLs are operator-configurable.