kanopi/firewall-symfony
Symfony integration for Kanopi Firewall that adds configurable request firewalls and access rules, letting you allow or deny traffic by IP, network, or custom criteria. Protect routes and enforce access policies directly from Symfony configuration.
Cache-Control: no-store-only response was silently cached by Pantheon's Fastly CDN, so all visitors received the same single-use ALTCHA challenge, the first solver passed, and everyone else looped. That failure mode is invisible in local testing, and the maintenance cost of tracking CDN cache semantics per host is exactly the kind of work a PM should be buying rather than owning.query_count rule variable in firewall 2.36, per-route policy) rather than an unbounded infrastructure project.kanopi:firewall:check is a scriptable allow/block/challenge/redirect gate. v1.3.0 fixes a serious correctness bug here: with no configuration present it exited 2, which means "challenged" — so a CI assertion that a URL is challenged could pass on an application with zero rules. It now exits 64 (unreadable configuration) and documents the full set (0 allowed, 1 blocked, 2 challenged, 3 redirected, 64, 70). This is a behaviour change in a minor release: any pipeline that treated 2 as success-on-empty-config was validating nothing and will now fail. That is a decision point for release managers, not just engineers.kanopi/firewall-symfony), not a Laravel package. For a Laravel product the realistic path is either the underlying kanopi/firewall library with a custom integration layer, or a different vendor. Treat "does this fit our stack" as an explicit roadmap decision with a build-cost estimate attached, rather than assuming drop-in parity.^2.36 floor pulls in fixes the bundle itself did not have to change: a solved challenge can no longer redirect off-site (open-redirect class), path normalisation closes //wp-json/… and /%77p-json/… rule-bypass encoding tricks, ASN rules actually fire (asn:16509 previously never matched), and rate-limit keys naming a capitalised field now count that field instead of collapsing every visitor into one shared counter. Several of these were silent in production. That is a prioritisation input for the next maintenance window.Consider it when:
no-store handling and serve challenged or blocked responses from the origin. This release exists specifically because that combination caused a site-wide challenge loop; if you are on v1.2.x behind such a CDN, the upgrade is effectively a correctness fix, not a feature pickup.2-on-empty-config behaviour.challenge.notice, RequestChallenged::addNotice()), rather than a CAPTCHA vendor contract.Look elsewhere, or plan for integration work, when:
kanopi/firewall ^2.36 floor — the upgrade is a floor bump, so the security fixes above come as a bundle.global.path_source: script_name. That setting is intended for WordPress's directly served files; a Symfony app always runs public/index.php, and script_name prepends the subdirectory to every path. The new doctor warning in this release flags it — treat that warning as blocking, not advisory.For executives (one paragraph): This is a maintenance release for the firewall layer that sits in front of our Symfony application, and it closes a customer-visible outage class. Behind Pantheon's CDN, our challenge page could be cached at the edge, so every visitor received the same single-use challenge — the first person to solve it got through and everyone after them was refused and sent back to the same page, indefinitely. v1.3.0 sends the full set of cache-prevention headers (no-store, private, no-cache, must-revalidate, max-age=0, Pragma, Expires, Surrogate-Control, CDN-Cache-Control) on every response the firewall writes, including error pages. It also moves us to a newer version of the underlying firewall library, which fixes an off-site redirect after a solved challenge, two URL-encoding bypasses of our access rules, an ASN matching bug where rules silently never fired, and a rate-limit bug that merged all visitors into one counter. None of these required code changes on our side; they arrive with the version floor. Cost is a composer bump plus a regression pass; risk is low but not zero because one CLI exit code changed.
For engineering (what to actually do):
composer require kanopi/firewall-symfony:^1.3, which pulls kanopi/firewall ^2.36 (from ^2.33). Confirm the PHP and Symfony constraints match your matrix before scheduling.kanopi:firewall:check with no configuration now exits 64 instead of 2. Any job that asserted "challenged" by matching 2 may have been passing on an empty ruleset. Re-baseline the gate against the documented codes: 0 allowed, 1 blocked, 2 challenged, 3 redirected, 64, 70.--help.global.path_source: script_name; on a subdirectory install it prefixes every path with the subdirectory and breaks rule matching silently. kanopi:firewall:check --script-name is now a declared option, so pipelines can pass it explicitly.blocked_response: http_exception routes through your error page.query_count (firewall 2.36) is now available as a rule variable; that is a small, separately-shippable win we can scope outside this upgrade.For the roadmap conversation: this release is a low-effort, high-leverage upgrade. The open product question is not whether to take it, but whether we are comfortable depending on a framework-specific bundle whose critical fix was a CDN cache-semantics issue — worth asking whether our own integration tests would have caught the challenge loop, and if not, adding an edge-caching check to the release checklist for any challenged or blocked route.
How can I help you explore Laravel packages today?