PackageTrack
Sign in Get early access

github.com/fabriziosalmi/caddy-waf

v0.4.1 #2839 most downloaded on Go modules fabriziosalmi/caddy-waf

What this package is like to depend on

Last release 3 days ago

21 Aug 2026

Release timing varies

gaps range from 8 days to 3 months

Most releases are documented

notes for 19 of 28 stable releases

Nothing withdrawn

no release was ever pulled

2 years old

246 releases · first in 2025

35 releases in the last 12 months

see the full history below

Release timeline

246 releases · Jan 2025 to Aug 2026
2026
Release Pre-release

Releases

latest 60 of 246
  1. v0.4.1 21 Aug 2026
    Release notes

    What's Changed

    Full Changelog: v0.4.0...v0.4.1

    Open source →
    Release notes

    Fixed

    • A response-target rule in an early phase no longer panics the request. A rule listing RESPONSE_HEADERS (or RESPONSE_HEADERS:<name>) in phase 1 or 2 — as several OWASP CRS rules do, e.g. 950010 — reached w.Header() on the nil http.ResponseWriter that handlePhase passes before the response exists. The panic was recovered into an HTTP 500, so every request behind the WAF failed. Response-header extraction is now nil-safe (mirroring the existing response-body guard): an out-of-phase response target degrades to a skipped target instead of crashing. Reported on OPNsense with OWASP rules (#144, #146).

    Changed

    • Bumped version constant wafVersion to v0.4.1.

    Internal

    • TestTorConfig_Provision is now hermetic — it serves the Tor exit-node list from a local httptest.Server instead of a live external CDN, removing the last third-party network dependency from CI (#147).
    Open source →
  2. v0.4.0 18 Aug 2026
    Release notes

    What's Changed

    • feat: input normalization for rule matching (v0.4.0) — close encoding evasion by @fabriziosalmi in #142

    Full Changelog: v0.3.11...v0.4.0

    Open source →
    Release notes

    Security

    Rule matching now inspects requests the way the application will decode them, closing encoding evasion. Confirmed empirically before the fix: a percent-encoded attack in a raw request target slipped past literal rule patterns. rules/sql-injection.json blocked id=1 UNION SELECT but not id=1 %55NION%20SELECT, nor %75nion, nor the same payload in an application/x-www-form-urlencoded body. Because the application decodes the request before acting on it, the WAF must match the decoded form. This affected the raw targets ARGS, URI, URL and BODY — the targets used by the bulk of the bundled and modular rules (SQLi, XSS, RCE, SSTI, SSRF).

    The fix is additive dual-match: each target is matched against the raw value first, then against a normalized copy, and the rule fires if either matches. Testing the raw value first is a mathematical guarantee that no rule which matches today can stop matching — the change only adds coverage, never removes it. Unencoded traffic runs no extra regex (the normalized pass is skipped when normalization does not change the value).

    Design followed ModSecurity/OWASP-CRS/Coraza prior art, including its guardrails:

    • Single-pass decoding, never recursive. %2555 decodes to the literal %55, matching what a single-decoding backend sees; decoding twice would manufacture false positives and diverge from reality.
    • Context-aware +: a space in query/body context, literal in the path portion of URI/URL, which are split on the first ?.
    • Lenient decoder: a malformed escape (%, %zz, a truncated %a) is left literal, never dropped — Go's url.QueryUnescape blanks the whole value on one bad byte, which would itself be a bypass.

    Added

    • Optional per-rule transformations field (ModSecurity/CRS-style pipeline): ["urlDecodeUni","removeNulls","replaceComments","htmlEntityDecode",…]. Absent means the per-target default chain (urlDecode, removeNulls, compressWhitespace); an explicit [] means match the raw value only. Names are case-insensitive, accept a t: prefix, and an unknown name fails at load time rather than silently doing nothing.
    • ModSecurity/CRS target aliases so SecLang-derived rule files resolve: REQUEST_HEADERSHEADERS, REQUEST_COOKIESCOOKIES, QUERY_STRINGARGS, REQUEST_URIURI, REQUEST_BODYBODY, REQUEST_FILENAMEPATH. Previously these fell through to "unknown extraction target" and were skipped, so 135 bundled rules (88 using REQUEST_COOKIES, 47 REQUEST_HEADERS) silently lost cookie/header coverage and one rule was fully inert.
    • transform.go with the transformation registry and lenient single-pass decoders; normalization_test.go and transform_test.go covering the closed evasions, the zero-regression property, per-rule transformations, the aliases, load-time validation, and — as an explicit test — the documented limit that double-encoding is not decoded twice.

    Honest limits

    Single-pass decoding does not catch double-encoding (correct against a single-decoding backend), and %uXXXX / overlong-UTF-8 are not decoded by the default pipeline. Cookie and header targets are not normalized by default; a rule that needs it can set transformations. See Input normalization.

    Migration

    This changes what every rule targeting ARGS/URI/URL/BODY sees. Because matching is additive (raw tested first), no existing rule stops firing and no config change is required. Rule authors who want the raw, un-normalized value only can set "transformations": [] on a rule. Custom rule files using ModSecurity target names now gain coverage they were silently missing.

    Changed

    • Bumped version constant wafVersion to v0.4.0.
    Open source →
  3. v0.3.11 18 Aug 2026
    Release notes

    What's Changed

    • docs: document the published container images by @fabriziosalmi in #134
    • build(deps): bump github.com/fsnotify/fsnotify from 1.9.0 to 1.10.1 in the go-minor-patch group across 1 directory by @dependabot[bot] in #135
    • build(deps): bump the actions group across 1 directory with 14 updates by @dependabot[bot] in #136
    • docs: stop presenting add-package as an install path for caddy-waf by @fabriziosalmi in #139
    • fix: metrics endpoint raced on shared counters and corrupted its response by @fabriziosalmi in #140
    • feat: whitelist_ip — exempt addresses from the IP-reputation checks by @fabriziosalmi in #141

    Full Changelog: v0.3.10...v0.3.11

    Open source →
    Release notes

    Added

    • whitelist_ip — exempt addresses from the IP-reputation checks without switching the WAF off for them. Accepts bare IPs, CIDR ranges, or the token private_ranges, and is repeatable:

      whitelist_ip private_ranges
      whitelist_ip 203.0.113.4 198.51.100.0/24
      

      Requested in #137 by @nozonyan: whitelist_countries blocks anything it cannot geolocate, which includes every address on the local network, so enabling it locks you out of your own service from inside the LAN. The only workarounds were geoip_fail_open — which also admits every unresolvable public address — or maintaining two site blocks with separate rule sets, with the risk of leaving the public one unprotected after a test.

      The exemption covers the checks that judge a client by where it comes from: the IP blacklist (including Tor exit nodes fed into it), whitelist_countries / block_countries, and block_asns. It deliberately does not cover the DNS blacklist (which judges the requested host, not the client), the rate limiter, or the regex rules in any phase. Exempting an address from geolocation is the fix; stopping inspection of its requests is not.

      private_ranges expands to exactly the set Caddy uses for its own placeholder — 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 127.0.0.1/8, fd00::/8, ::1. Identical rather than "improved": a WAF and the server in front of it disagreeing about which addresses are private is how bypasses get built. An entry that does not parse fails startup rather than being skipped with a warning.

    Security notes on the design

    • The whitelist matches the peer address only, never X-Forwarded-For. This is the deliberate opposite of the blacklist, which checks the peer address and every forwarded hop. When blocking, consulting extra addresses can only block more; when allowing, honouring a client-supplied header would let anyone send X-Forwarded-For: 10.0.0.1 and exempt themselves from the blacklist, the country filter and the ASN filter in a single header. Covered by TestWhitelistIgnoresForwardedHeaders.
    • private_ranges is only safe when caddy-waf is the edge. Because the check is on the peer address, running behind another proxy makes the peer that proxy — typically a private or loopback address — which would exempt every request passing through it. The WAF now logs a warning at startup when private_ranges is whitelisted, and docs/configuration.md documents the trap.

    Changed

    • Bumped version constant wafVersion to v0.3.11.
    Open source →
  4. v0.3.11-0.20260728203530-3d2d926b4f0d 28 Jul 2026 pre-release

    Nothing published for this version

  5. v0.3.10 28 Jul 2026
    Release notes

    What's Changed

    • feat: publish container images to ghcr, and make docker build use the source by @fabriziosalmi in #133

    Full Changelog: v0.3.9...v0.3.10

    Open source →
    Release notes

    Fixed

    • docker build . ignored your source tree. The Dockerfile ran git clone https://github.com/fabriziosalmi/caddy-waf.git and built that, so the build context was never used: the image contained whatever happened to be on main at build time, could not be pinned to a version, and a CI image build would have tested the wrong code. The build context is now the source.
    • The builder image was older than go.mod requires. golang:1.24-alpine against a module declaring go 1.25.1; it only worked because GOTOOLCHAIN=auto silently downloaded a newer toolchain mid-build. Now golang:1.26-alpine.

    Added

    • Published container images at ghcr.io/fabriziosalmi/caddy-waf, built on release tags for linux/amd64 and linux/arm64. Tagged by version as well as latest, so a deployment can pin — latest alone would leave anyone who pulled before a security release with no way to name the image they wanted.
    • .github/workflows/docker.yml builds the image on pull requests without pushing, and asserts caddy list-modules reports http.handlers.waf rather than trusting a green build. Nothing built this image before, which is how it came to clone the repository instead of using the context, and to pin a stale Go version.
    • .dockerignore extended so the context excludes node_modules, docs/, tests and helper scripts. ui/ is deliberately kept: assets.go embeds it behind the with_ui build tag.

    Changed

    • Bumped version constant wafVersion to v0.3.10.
    Open source →
  6. v0.3.9 28 Jul 2026
    Release notes

    What's Changed

    • fix: ReloadRules deadlock, DNS blacklist bypass, IP blacklist data race by @fabriziosalmi in #132

    Full Changelog: v0.3.8...v0.3.9

    Open source →
    Release notes

    Security

    Two further defects in the same subsystem, one of them the sibling of a bug fixed in v0.3.7. Both were surfaced by an adversarial sweep that drives real requests through ServeHTTP and asks whether the client is actually refused, rather than whether a helper returns true.

    • ReloadRules had the identical self-deadlock fixed in ReloadConfig. It took m.mu and then called loadRules, which takes m.mu again; the goroutine blocked forever while owning the write lock, so every later request stalled on the RLock in the request path. This is the primary hot-reload branch: startFileWatcher routes any changed path containing "rule" to ReloadRules, which means editing rules.json — the case docs/dynamicupdates.md documents — wedged the server. v0.3.7 fixed one branch of the watcher and missed the other. Found by the automated review on #130.

    • The DNS blacklist was bypassable, and inert on non-default ports. isDNSBlacklisted only lowercased and trimmed the Host header, so evil.example:8080 and evil.example. both missed an entry for evil.example. r.Host carries the port whenever the site is served on anything other than 80/443 — which every example in this repository does — so those deployments had no DNS filtering at all; and a client may send an explicit :443 even on the default port, making it a one-header bypass. Hosts are now normalised (lowercase, port stripped, trailing dot removed, IPv6 brackets removed).

    Fixed

    • Data race on the IP blacklist during hot reload. ReloadConfig swapped m.ipBlacklist under m.mu, but isIPBlacklisted read it without taking the lock, so the swap never synchronised with in-flight requests. The read is now under RLock, mirroring isDNSBlacklisted. Found by the automated review on #130.
    • Documentation described the pre-v0.3.8 X-Forwarded-For behaviour ("first XFF value if present, otherwise r.RemoteAddr"), which stopped being true when that bypass was closed.

    Added

    • TestReloadRulesDoesNotDeadlock — the branch v0.3.7 missed, asserted on a deadline and followed by a reader that must get through.
    • The full suite now passes under -race.

    Changed

    • Documented Go requirement corrected to 1.25.1. go.mod declares it because caddy/v2 v2.11.4 and go.step.sm/crypto require it and Go propagates the maximum; forcing 1.25.0 breaks the build.
    • Bumped version constant wafVersion to v0.3.9.
    Open source →
  7. v0.3.8 28 Jul 2026
    Release notes

    What's Changed

    • fix: a forged X-Forwarded-For bypassed the IP blacklist entirely by @fabriziosalmi in #131

    Full Changelog: v0.3.7...v0.3.8

    Open source →
    Release notes

    Security

    A single request header bypassed the IP blacklist entirely. Phase 1 consulted X-Forwarded-For instead of r.RemoteAddr whenever the header was present:

    if xForwardedFor != "" {
        if m.isIPBlacklisted(firstIP) { block }
        // no else -- r.RemoteAddr was never checked
    } else {
        if m.isIPBlacklisted(r.RemoteAddr) { block }
    }
    

    Any blacklisted client could send X-Forwarded-For: 8.8.8.8 and skip the check. No tooling, no preconditions, no authentication — one arbitrary header. Demonstrated end to end: the same client is refused with 403 without the header and served 200 with it.

    The peer address is now checked first and unconditionally, since it is the only value a client cannot forge, and the forwarded chain is checked in addition rather than instead. Checking more addresses can only block more, never less. A client can therefore blacklist itself by forging a listed address, which is harmless. Deciding which forwarded values to trust requires a trusted_proxies option and is tracked in #94.

    This was masked until v0.3.7: before that the blacklist was never populated at all (see v0.3.7), so nothing was bypassable because nothing was enforced. Fixing enforcement made this the live bypass, which is why it ships one release later.

    Covered by GHSA-w6gv-76q4-prqg, updated to reflect v0.3.8 as the patched version.

    Added

    • TestBlacklistedIPIsBlockedEndToEnd/a_forged_X-Forwarded-For_cannot_skip_the_check — a blacklisted peer sending a clean X-Forwarded-For must still be refused.

    Changed

    • Bumped version constant wafVersion to v0.3.8.
    Open source →
  8. v0.3.7 28 Jul 2026
    Release notes

    What's Changed

    • fix: the IP blacklist never blocked, and hot reload deadlocked the server by @fabriziosalmi in #130

    Full Changelog: v0.3.6...v0.3.7

    Open source →
    Release notes

    Security

    Two defects in the blacklist subsystem, both silent. Reported in substance by @doogienz in discussion #96 on 2026-05-21, with the log evidence that pinned it down.

    • The IP blacklist never blocked anything. loadIPBlacklist took the trie by value, and both callers — Provision and ReloadConfig — dereferenced their pointer to satisfy that signature. Every Insert therefore landed in a copy discarded on return: the trie the middleware consults stayed empty, while the loader still logged IP blacklist loaded {"valid_entries": N}. Any deployment relying on ip_blacklist_file, including the 223,770-entry list bundled with the project, had no IP filtering at all and no indication of it. Present since v0.0.7 (commit c905277, "switch to go-trie", 2025-10-10) — 15 releases.

    • Hot-reloading a blacklist deadlocked the server. ReloadConfig held m.mu and then called loadRules, which takes m.mu again; on Go's non-reentrant RWMutex the goroutine blocked forever while still owning the write lock. Since isDNSBlacklisted takes m.mu.RLock() on every request, all subsequent requests blocked forever — no crash, no log line. The file watcher calls ReloadConfig whenever ip_blacklist_file or dns_blacklist_file changes, and the documented Tor setup (docs/dynamicupdates.md) points ip_blacklist_file at the file the Tor fetcher rewrites every update_interval (default 24h), so the configuration the docs recommend wedges the server within a day of starting, unattended.

    Both are fixed: the trie is passed by pointer, and ReloadConfig builds the new structures outside the lock, swaps them under it, and never holds m.mu across a call that takes it again.

    Added

    • blacklist_enforcement_test.go — four regression tests: the trie is actually populated (IPv4, IPv6, CIDR, with and without a port), the reload path repopulates it, ReloadConfig completes and releases the lock under a deadline, and a full ServeHTTP pass confirms a blacklisted client is refused, never reaches the upstream, and that X-Forwarded-For is honoured.

    Changed

    • Bumped version constant wafVersion to v0.3.7.
    Open source →
  9. v0.3.6 28 Jul 2026
    Release notes

    What's Changed

    Full Changelog: v0.3.5...v0.3.6

    Open source →
    Release notes

    Security

    Cleared the Dependabot backlog on the default branch: 25 of 30 open alerts — 7 critical, 5 high, 13 moderate. Every bump was verified by building and testing, not by trusting the suggestion.

    Module From To Alerts closed
    golang.org/x/crypto v0.49.0 v0.52.0 7 critical, 2 high, 4 moderate
    github.com/caddyserver/caddy/v2 v2.11.2 v2.11.4 2 high, 3 moderate
    google.golang.org/grpc v1.79.3 v1.82.1 1 high
    golang.org/x/net v0.52.0 v0.55.0 1 moderate
    github.com/quic-go/quic-go v0.59.0 v0.59.1 1 moderate
    go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 v1.44.0 1 moderate
    go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 v0.20.0 1 moderate

    No source changes were required. go build, go vet and the full unit suite pass, and xcaddy build against the bumped tree produces a working Caddy v2.11.4 binary that registers http.handlers.waf.

    Not fixed, and why

    Five alerts remain open. Leaving them undocumented would be worse than leaving them open.

    • github.com/google/cel-go (moderate, GHSA-gcjh-h69q-9w9g) — the suggested v0.29.0 does not compile against Caddy v2.11.4: interpreter.NewCall changed from []interpreter.Interpretable to []interpreter.InterpretableV2, and caddyhttp/celmatcher.go still passes the former. Caddy's own go.mod pins v0.28.1. Taking the bump would trade a moderate transitive advisory for a build that does not exist. Blocked until Caddy updates.
    • vite ×3 (1 high, 2 moderate) and esbuild ×1 (moderate) — introduced in v0.3.5 by the package-lock.json for the VitePress docs site. All four are development-server issues (arbitrary origins reading dev-server responses; server.fs.deny bypass on Windows; NTLMv2 disclosure via UNC paths on Windows; path traversal in optimized-deps .map handling). CI only ever runs vitepress build, the published site is static HTML, and npm audit --omit=dev reports zero. The fix requires vite ≥ 6.4.3, which no stable VitePress pulls — latest is 1.6.4 and pins vite ^5.4.14; only the 2.0.0-alpha line moves to vite 6. Running an alpha documentation generator to silence dev-only advisories is the worse trade.

    Changed

    • Documentation references to the pinned Caddy version updated from v2.11.2 to v2.11.4.
    • Bumped version constant wafVersion to v0.3.6.
    Open source →
  10. v0.3.6-0.20260728112428-b1658e5e31d7 28 Jul 2026 pre-release

    Nothing published for this version

  11. v0.3.6-0.20260728101137-bb8fa2de5692 28 Jul 2026 pre-release

    Nothing published for this version

  12. v0.3.5 28 Jul 2026
    Release notes

    What's Changed

    • docs: refresh SECURITY.md supported versions and reporting channel by @fabriziosalmi in #120
    • fix: make module scannable by Caddy's package registry, bump to v0.3.5 by @fabriziosalmi in #121

    Full Changelog: v0.3.4...v0.3.5

    Open source →
    Release notes

    Fixed

    • Caddy package registry could not scan this module. caddy.RegisterModule(&Middleware{}) parses as an ast.UnaryExpr wrapping the literal, and the static analyzer behind https://caddyserver.com/account/register-package accepts only a composite literal or new(). Every registration attempt therefore failed with the opaque portal error unable to scan modules in package github.com/fabriziosalmi/caddy-waf, which never names the offending line — leaving the module absent from https://caddyserver.com/download and caddy add-package github.com/fabriziosalmi/caddy-waf returning HTTP 400. Both caddy.RegisterModule and ModuleInfo.New now use new(Middleware).

      The two forms are semantically identical (each allocates a zeroed Middleware and yields a pointer), so there is no behavioural change. The pointer is required regardless: CaddyModule has a pointer receiver and Middleware carries mutexes that must not be copied.

      Diagnosis courtesy of the Caddy community thread Unable to register module in the portal, where the underlying analyzer error is quoted as unexpected argument to RegisterModule(): &ast.UnaryExpr{...} - expect either composite literal or new().

    Added

    • TestRegisterModuleArgumentIsScannable — parses the package's own AST and asserts the caddy.RegisterModule argument stays a composite literal or new(), so the registry constraint cannot silently regress on a future edit. Verified to fail against the v0.3.4 pattern and pass against the fix.

    Changed

    • Rewrote CADDY_MODULE_REGISTRATION.md, which was stale (referenced v0.0.6 and Caddy v2.9.1) and speculated that the failures were server-side and "may resolve automatically". It now records the verified root cause and the maintenance notes.
    • Bumped version constant wafVersion to v0.3.5.

    Registered

    With the scan fixed, github.com/fabriziosalmi/caddy-waf was claimed in Caddy's package registry on 2026-07-28 at 10:05:52 UTC, at v0.3.5. The build service now serves it (GET /api/download?p=github.com%2Ffabriziosalmi%2Fcaddy-waf returns a binary instead of HTTP 400), so caddy add-package github.com/fabriziosalmi/caddy-waf works and the module is selectable on https://caddyserver.com/download. README.md, docs/installation.md and docs/add-package-guide.md updated accordingly — they previously documented the install path as unavailable.

    Note the module documentation shown on caddyserver.com is extracted from the doc comment on the Middleware struct in types.go.

    Open source →
  13. v0.3.4 28 Jul 2026
    Release notes

    What's Changed

    Full Changelog: v0.3.3...v0.3.4

    Open source →
    Release notes

    Security

    • Fixed unbounded response buffering (GHSA-gfj3-cmff-q8wh, CWE-400, CVSS 3.1 7.5 high, remote unauthenticated DoS). Up to and including v0.3.3, responseRecorder accumulated the entire upstream response body in an in-memory bytes.Buffer before releasing a single byte to the client, with no configurable or hard-coded ceiling. A single unauthenticated request for a large or streaming resource made the Caddy process's heap grow in step with the response size, so an attacker could OOM-kill the process and take down every site served by that instance. Reported by @EQSTLab.

      The response body is now buffered only when it can actually be used, and only up to a bound:

      • No Phase 4 rules ⇒ no buffering. ServeHTTP now asks hasResponseBodyRules() before capturing anything; with no RESPONSE_BODY rule loaded the recorder is a pass-through that forwards writes as they arrive. The bundled rules.json has no Phase 4 rules, so the default configuration buffers nothing at all and no longer defeats HTTP streaming.
      • Hard ceiling of max_response_body_size (new setting, default 10 MiB). When a response outgrows the budget, the recorder writes out what it holds and streams the remainder straight to the client, so peak memory is bounded by the limit rather than by the response size.
      • An upstream flush releases the buffer instead of stalling, so server-sent events and chunked streaming work through a WAF-protected route rather than being held until the budget fills.
      • A released response cannot be blocked, since part of it is already on the wire. Phase 4 is skipped in that case and logged at warn ("Response body exceeded the WAF inspection limit; Phase 4 rules were not applied") rather than scoring a truncated body and reporting the response as vetted.

      Measured on a 512 MiB response through a WAF-protected route: heap allocated during ServeHTTP drops from 1535 MiB to 0 MiB, with all 512 MiB still delivered to the client.

    Added

    • max_response_body_size (Caddyfile directive and JSON field, default 10485760) — ceiling on how much of the response body is retained for Phase 4 inspection. Validated as non-negative by Validate; 0 selects the default.
    • max_request_body_size is now settable from the Caddyfile as well, not only from JSON.
    • responseRecorder implements http.Flusher.

    Fixed

    • A Phase 4 block no longer swallows the configured custom_response body. ServeHTTP wrote the custom response into the recorder, whose buffer is discarded on the blocked path, so the client received an empty body; it now writes to the real ResponseWriter.

    Known limitation

    • The status code of a Phase 3/4 block is still not applied: responseRecorder.WriteHeader forwards the status to the underlying ResponseWriter as soon as the upstream sets it, so by the time the response phases run the status line is already committed and a block surfaces as 200 with the custom body. This is pre-existing behaviour, unrelated to the advisory above, and is tracked separately.

    Changed

    • Bumped version constant wafVersion to v0.3.4.
    Open source →
  14. v0.3.3 29 Apr 2026

    Nothing published for this version

  15. v0.3.2 26 Apr 2026
    Release notes

    Security

    Patched 3 critical and 10 high severity Dependabot alerts by upgrading the affected dependencies to their fixed versions:

    • github.com/caddyserver/caddy/v2 v2.10.2 → v2.11.2 — fixes 4 high (FastCGI split_path Unicode case-folding bypass, MatchHost case-sensitivity bypass on >100 hosts, MatchPath %xx case normalization bypass, mTLS silent fail-open on missing CA file) and 2 medium (admin API CSRF on /load, file matcher glob sanitization).
    • google.golang.org/grpc v1.78.0 → v1.79.3 — fixes 1 critical (authorization bypass via missing leading slash in :path).
    • github.com/jackc/pgx/v5 v5.8.0 → v5.9.2 — fixes 1 critical (memory-safety) and 1 low (SQL injection via dollar-quoted placeholder confusion).
    • github.com/smallstep/certificates v0.29.0 → v0.30.2 — fixes 1 critical (unauthenticated certificate issuance via SCEP UpdateReq MessageType=18) and 1 low (TPM EKU validation index-out-of-bounds panic).
    • go.opentelemetry.io/otel v1.39.0 → v1.43.0 — fixes 1 high (multi-value baggage header DoS amplification).
    • go.opentelemetry.io/otel/sdk v1.39.0 → v1.43.0 — fixes 2 high (BSD kenv PATH hijacking; arbitrary code execution via PATH hijacking).
    • github.com/go-jose/go-jose/v4 v4.1.3 → v4.1.4 — fixes 1 high (JWE decryption panic).
    • github.com/go-jose/go-jose/v3 v3.0.4 → v3.0.5 — fixes 1 high (JWE decryption panic).
    • github.com/slackhq/nebula v1.9.7 → v1.10.3 — fixes 1 high (blocklist bypass via ECDSA signature malleability).
    • github.com/cloudflare/circl upgraded to v1.6.3 — fixes 1 low (incorrect secp384r1 CombinedMult calculation).
    • filippo.io/edwards25519 upgraded to v1.2.0 — fixes 1 low (MultiScalarMult invalid results when receiver is not the identity).

    No source-code changes required; the WAF compiles and the full unit test suite passes against the upgraded dependency tree.

    Changed

    • Bumped version constant wafVersion to v0.3.2.
    Open source →
  16. v0.3.1 26 Apr 2026
    Release notes

    Documentation

    • Rewrote README.md, MODULE.md, caddyfile.example, and the entire docs/ tree to be 1:1 accurate with the current source code.
    • docs/configuration.md now lists every Caddyfile directive recognised by config.go, every JSON-only field on the Middleware struct, the precise Phase 1 evaluation order, and the parser- vs. Provision-time defaults.
    • docs/rules.md documents the JSON tag mismatch on Rule.Action (struct tag is mode, while the bundled rule files commonly use action), so authors know which key is actually parsed.
    • docs/ratelimit.md corrects the match_all_paths semantics to match ratelimiter.go (true ⇒ rate-limit every request; false + non-empty paths ⇒ rate-limit only matching paths).
    • docs/dynamicupdates.md adds an explicit reload matrix showing which settings are reloaded by fsnotify and which require caddy reload.
    • docs/metrics.md documents the actual response schema returned by handleMetricsRequest and clarifies that all counters are process-local and reset on restart.
    • docs/prometheus.md switches the example exporter from Counter.inc(absolute) to Gauge.set(absolute) to match the WAF's monotonic process-local counter semantics.
    • caddyfile.example no longer references non-existent directives (country_block, custom_response { … } block form).
    • Removed emoji from all user-facing documentation.

    Changed

    • Bumped version constant wafVersion to v0.3.1.
    Open source →
  17. v0.3.0 22 Feb 2026
    Release notes

    Fixed

    • Resolved duplicate response headers when a custom block response was emitted.
    • IP blacklist loader now accepts CIDR notation in addition to single IPs (net.ParseCIDR is tried before net.ParseIP).
    Open source →
  18. v0.2.1-0.20260117182623-c837101335a0 17 Jan 2026 pre-release

    Nothing published for this version

  19. v0.2.0 17 Jan 2026
    Release notes

    Fixed

    • Fixed potential panic in isIPBlacklisted() when parsing malformed IP addresses - now uses netip.ParseAddr() instead of netip.MustParseAddr().
    • Fixed type assertion panic in processRuleMatch() - now uses safe getLogID() helper function.
    • Fixed potential panic in extractIP() and getClientIP() when handling empty or malformed input.

    Added

    • Added 30-second HTTP client timeout in tor.go to prevent hanging requests during Tor exit node list fetches.
    • Added comprehensive input validation in Validate() method for negative threshold/limit values.
    • Added parameter validation in NewRateLimiter() to ensure positive values.

    Changed

    • Updated installation documentation to clarify that caddy add-package is not available (module not registered in Caddy's package registry).
    • Reordered installation methods in documentation to recommend Quick Script and xcaddy as primary options.
    • Updated CADDY_MODULE_REGISTRATION.md with current registration status.

    Documentation

    • Added warnings about caddy add-package limitations in README.md, installation.md, and add-package-guide.md.
    Open source →
  20. v0.1.6 06 Jan 2026
    Release notes

    Fixed

    • Minor bug fixes and stability improvements.
    Open source →
  21. v0.1.6-0.20251229091634-cf45542c7e07 29 Dec 2025 pre-release

    Nothing published for this version

  22. v0.1.5 08 Dec 2025
    Release notes

    Fixed

    • Fixed critical bug where POST request bodies were lost or truncated by using io.MultiReader to restore the full body stream (fixes #76).
    Open source →
  23. v0.1.4 06 Dec 2025
    Release notes

    Security

    • Fixed Panic vulnerability in quic-go by upgrading to v0.54.0 (requires Caddy v2.10.x and Go 1.25).
    • Addressed Dependabot Alert #7.

    Changed

    • Upgraded Caddy dependency to v2.10.2.
    • Upgraded Go requirement to 1.25.
    • Improved CI workflows to use Go 1.25 for build and release.
    Open source →
  24. v0.1.3 06 Dec 2025
    Release notes

    Fixed

    • Downgraded quic-go to v0.48.2 and Caddy to v2.9.1 to temporarily resolve Go version conflicts (superseded by v0.1.4).
    • Fixed import grouping for gci linter compliance.
    • Fixed GitHub Actions release workflow.
    Open source →
  25. v0.1.2 06 Dec 2025
    Release notes

    Added

    • SOTA Engineering patterns (Zero-Copy headers, Wait-Free Ring Buffer, Circuit Breaker).
    • ASN Blocking support.
    • Configurable Request Body size limit.
    • GeoIP Fail Open configuration.
    Open source →
  26. v0.1.0 06 Dec 2025

    Nothing published for this version

  27. v0.0.10-0.20251206213732-47e05e907e5e 06 Dec 2025 pre-release

    Nothing published for this version

  28. v0.0.9 06 Dec 2025

    Nothing published for this version

  29. v0.0.9-0.20251023131337-e98fd16392c6 23 Oct 2025 pre-release

    Nothing published for this version

  30. v0.0.8 20 Oct 2025

    Nothing published for this version

  31. v0.0.7 15 Oct 2025

    Nothing published for this version

  32. v0.0.7-0.20251012173338-1207bd7a6dd3 12 Oct 2025 pre-release

    Nothing published for this version

  33. v0.0.7-0.20251011215047-485c86fdbcbb 11 Oct 2025 pre-release

    Nothing published for this version

  34. v0.0.7-0.20251011075419-8d5af6be5fda 11 Oct 2025 pre-release

    Nothing published for this version

  35. v0.0.7-0.20250914121224-8685d03503a5 14 Sep 2025 pre-release

    Nothing published for this version

  36. v0.0.6 13 Jul 2025

    Nothing published for this version

  37. v0.0.6-0.20250502053323-bae17679f1cf 02 May 2025 pre-release

    Nothing published for this version

  38. v0.0.5 30 Apr 2025

    Nothing published for this version

  39. v0.0.5-0.20250430091917-fe84fbb5c556 30 Apr 2025 pre-release

    Nothing published for this version

  40. v0.0.5-0.20250313100929-bf367b5c53c2 13 Mar 2025 pre-release

    Nothing published for this version

  41. v0.0.4 09 Feb 2025

    Nothing published for this version

  42. v0.0.3 09 Feb 2025

    Nothing published for this version

  43. v0.0.0-20250209153245-4f31673cb54f 09 Feb 2025 pre-release

    Nothing published for this version

  44. v0.0.0-20250202233915-6b94875c0aea 02 Feb 2025 pre-release

    Nothing published for this version

  45. v0.0.0-20250202215558-39d3773524c0 02 Feb 2025 pre-release

    Nothing published for this version

  46. v0.0.0-20250202095321-7115c73c792b 02 Feb 2025 pre-release

    Nothing published for this version

  47. v0.0.0-20250201234947-d730f0acdcb0 01 Feb 2025 pre-release

    Nothing published for this version

  48. v0.0.0-20250201234218-dec2e4dba588 01 Feb 2025 pre-release

    Nothing published for this version

  49. v0.0.0-20250201000951-f01d59ca250f 01 Feb 2025 pre-release

    Nothing published for this version

  50. v0.0.0-20250201000618-40d023343513 01 Feb 2025 pre-release

    Nothing published for this version

  51. v0.0.0-20250129225620-9ec63810155c 29 Jan 2025 pre-release

    Nothing published for this version

  52. v0.0.0-20250129221749-b39b0fb2e6f7 29 Jan 2025 pre-release

    Nothing published for this version

  53. v0.0.0-20250129214658-e1a013ebad25 29 Jan 2025 pre-release

    Nothing published for this version

  54. v0.0.0-20250129191903-b7c7f4e49989 29 Jan 2025 pre-release

    Nothing published for this version

  55. v0.0.0-20250129182107-3d83116dbc0b 29 Jan 2025 pre-release

    Nothing published for this version

  56. v0.0.0-20250129181706-297fcab5bc6c 29 Jan 2025 pre-release

    Nothing published for this version

  57. v0.0.0-20250129181315-44c4a30c07cd 29 Jan 2025 pre-release

    Nothing published for this version

  58. v0.0.0-20250129154313-859a9f1ed999 29 Jan 2025 pre-release

    Nothing published for this version

  59. v0.0.0-20250129143035-6974ef87022b 29 Jan 2025 pre-release

    Nothing published for this version

  60. v0.0.0-20250129131750-8aca85cf7ddb 29 Jan 2025 pre-release

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive