rennf93/laravel-guard
Laravel Guard is a lightweight package for adding configurable guard-based access control to Laravel apps. It integrates with Laravel’s authentication system, making it easy to define guards, manage providers, and protect routes with simple configuration.
GuardMiddleware::finish() was typed Illuminate\Http\Response, so any route returning response()->json(...), a redirect, or a streamed download could throw a TypeError on the pass-through path. That made the package effectively unsafe for the API and file-download routes most products actually expose. With the signature widened to Symfony\Component\HttpFoundation\Response, "adopt guard middleware on the whole HTTP surface, not just HTML pages" becomes a defensible roadmap decision rather than a gamble.guard-core-php; the engine owns the detection semantics. Buying this means inheriting a reference-driven rule engine and a documented agent extension path (rennf93/guard-agent-php) instead of owning regex scanning, IP canonicalization, and list precedence logic ourselves — a strong argument for build-vs-buy on the "we'll just write middleware" option.SecurityConfig::customResponseModifier now runs on pass-through responses, including excluded paths and all-checks-bypass responses, and never double-applies. That turns a single config hook into the product-wide mechanism for injecting CSP nonces, HSTS, or per-tenant headers onto every response — including the ones we deliberately exclude from detection. That is a product-level decision (one header contract across authenticated APIs, static assets, and bypassed routes), not an implementation detail.JsonResponse) gives a credible "verified for our response types" statement for a release gate — directly usable in a go/no-go review for a customer-facing API launch.detectionMaxScanSeconds (default 10.0, 0.1–60.0) produces a weighted pattern_timeout threat when exhausted. That is a new, actionable signal: expensive requests get flagged instead of silently scanned to completion. It also opens a tuning decision — cap CPU on hot endpoints vs. accept slower scans — and a logging decision, since passive-mode log wording changed and any log-based alerting/dashboards we own must be updated.enableAgent, enableDynamicRules, dynamicRuleInterval, enableEnrichment, and lifecycle hooks. But the engine now requires enableAgent: true for dynamic rules and enrichment. So "turn on adaptive rules" becomes a planned feature with a dependency (an agent handler) rather than a config flag someone flips in a PR.ip_blacklist rules are now timed bans for ipBanDuration seconds rather than merges into the static list. These are policy semantics — who gets blocked, for how long, and whether a route can override the global list — that product and support must agree on, and they affect ban-appeal and false-positive handling.Consider adoption when:
TypeError fix is the specific precondition here; on any earlier release, treat JSON/streamed routes as unsupported until validated.customResponseModifier. This is the strongest reason to take 1.6.0 specifically.composer validate --strict, composer audit clean, 168/168 harness checks, 100% line coverage gate.guard-core-php ^4.4.0. This is mandatory, not optional — applyResponseModifier() and the 4.4.0 config validation do not exist in earlier engines.Look elsewhere or defer when:
X-Forwarded-For, mapped peers inside a trusted IPv4 CIDR no longer trusted, list entries canonicalized), dynamic rule versions no longer stacking, ip_blacklist dynamic rules becoming timed bans, and new pattern_timeout flags on expensive requests.SecurityConfig sets enableDynamicRules or enableEnrichment without enableAgent: true — this now fails validation and the engine throws at build time. Blocking upgrade work until configs are corrected.[PASSIVE MODE] Suspicious activity detected from <ip>: ... - Reason: <reason> - Headers: ... format changed; log-based detectors, dashboards, or SIEM parsers must be updated in lockstep.Set-Cookie, cannot change a body that isn't string-readable (status and headers only), preserves original header value lists when unchanged, and leaves the response untouched if the modifier throws. It is a header/status hook, not a transformation layer.rennf93/guard-agent-php is only under suggest, so agent paths are optional-by-design and not a hard dependency.For executives (one paragraph): v1.6.0 makes our Laravel security middleware safe to run on the entire product surface, including JSON APIs, redirects, and file downloads — previously these could fail outright with a TypeError, which quietly restricted where we could deploy it. The same release lets us enforce one response-header policy (CSP, HSTS, tenant headers) uniformly, even on routes we deliberately exclude from scanning, and adds a CPU-time budget so a single pathological request can be flagged rather than silently consuming the worker. Cost is a mandatory engine bump plus a short config-and-logging migration. Verdict: adopt before the next API launch; it converts a partial-coverage tool into a whole-surface control.
For engineering leads: The change is small in our code and non-trivial in behavior. Two signatures moved from Illuminate\Http\Response to Symfony\Component\HttpFoundation\Response, which fixes pass-through for JsonResponse, RedirectResponse, and StreamedResponse; the block path still returns Illuminate\Http\Response from the translator, so block-handling callers are unaffected. finish() now calls GuardEngine::applyResponseModifier() between the engine security headers and the CORS verdict headers, so the modifier applies to pass-through responses and never twice to an engine-modified one. Nothing is read from the response when no modifier is configured. Plan work for: (1) adding enableAgent: true wherever enableDynamicRules or enableEnrichment is set, (2) reviewing IP list configuration against the new precedence rules, (3) re-baselining any ban or rate-limit expectations now that client-IP canonicalization is stricter — some clients will match where they previously didn't, (4) auditing dynamic rule assumptions now that versions no longer stack and ip_blacklist rules are timed bans, and (5) updating passive-mode log matchers to the new wording. Verification is credible: 168/168 checks green including the three response-kind regressions and the modifier-on-JsonResponse case, composer validate --strict and composer audit clean, 100% line coverage.
For security and support: Two policy-visible shifts. First, list precedence is now reference-faithful — a configured whitelist decides alone, blacklist applies only when no whitelist exists, a route whitelist skips the global lists for that request, and a route blacklist is consulted only when the route has no whitelist. Second, client-IP canonicalization changed: X-Forwarded-For entries lose their port, mapped peers inside an IPv4 CIDR of trustedProxies are no longer trusted, and list matching canonicalizes entries. Expect a small number of verdict changes on the first deploy; treat it as a config review and an appeal-handling note, not an outage. Also note detectionMaxScanSeconds can now flag a request as pattern_timeout where it previously completed scanning — decide the default per route tier rather than leaving 10.0 everywhere by accident.
Recommendation: Upgrade to v1.6.0, gate it on a config audit (agent flags, IP lists, trusted proxies) and a log-parser update, and treat the response-modifier coverage as the enabling feature for a uniform security-header standard across all response types. Do not advertise response-body transformation — the modifier is header-and-status only, cannot see Set-Cookie, and no-ops on non-string bodies and on modifier exceptions.
How can I help you explore Laravel packages today?