enumag/csrf-route-bundle
enumag/csrf-route-bundle (GenedysCsrfRouteBundle) secures Symfony 3 routes against CSRF attacks without forms. Add a csrf_token option to any route; the bundle's router appends a token query parameter and a controller listener validates it on incoming requests.
Framework mismatch is the decisive finding. Despite the brief's "Laravel/PHP package" framing, enumag/csrf-route-bundle is a Symfony 3 bundle (published as genedys/csrf-route-bundle). It registers a compiler pass in Symfony's DI container, decorates Symfony's router service, reads Symfony routing options, and validates in a kernel request/controller listener. There is no Laravel ServiceProvider, no publishable config, no facade, and no Illuminate\Foundation-compatible middleware. It cannot be composer required into a Laravel app in any meaningful sense.
Architecture fit: The problem it targets — per-route CSRF validation outside of form submissions (logout links, one-click delete/archive/toggle actions, XHR mutations, GET-triggered state changes) — is a real Laravel-relevant gap in legacy or hurriedly-built applications. Laravel's built-in VerifyCsrfToken middleware already covers POST/PUT/PATCH/DELETE, and @csrf/csrf_token()/X-XSRF-TOKEN cover the form and XHR cases. What Laravel does not give you out of the box is per-route opt-in protection for GET routes or a declarative route-level annotation. That is genuinely a ~40–80 line custom middleware in Laravel. So the package's contribution to a Laravel team is a design precedent, not an installable asset.
Integration feasibility: Effectively zero for direct adoption. Concretely:
RouterInterface, RouteCollection, and RequestContext; Laravel's router is a different abstraction with different route action semantics.@CsrfToken) requires Doctrine annotations plus Symfony's annotation route loader — a stack Laravel does not run.symfony/http-kernel, symfony/routing, and symfony/security-csrf into a Laravel app and bridging kernels. That is a security-debt-for-security-value trade, which should be rejected on principle.Technical risk: High, and concentrated in the trust boundary. CSRF tokens sit directly on the authentication/authorization path; an unmaintained, unauditable dependency there is a bad risk posture even for small code. Signals:
readme, score 0.03 — zero production validation, zero downstream bug reports (which is not the same as zero bugs).enumag/csrf-route-bundle) does not match the README's install target (genedys/csrf-route-bundle). That is a supply-chain identity mismatch and must be resolved before the name ever appears in a lockfile review. It suggests a fork whose steward and patch cadence are unknown.hash_equals constant-time comparison, session binding, or rotation-on-privilege-change — the three things an auditor will ask about.Key questions to answer before spending any effort:
hash_equals, and what is the token lifetime/rotation policy? (We need parity with or improvement over the precedent.)X-CSRF-TOKEN vs X-XSRF-TOKEN) and cookie/SameSite handling.Stack fit: Reject as a Composer dependency. Adopt as a reference implementation for a native Laravel middleware. The transferable surface API is clean and worth copying: per-route opt-in via route action/metadata, token attached at URL-generation time, validated before the controller runs, with configurable field name, intention/scope, and HTTP methods.
Migration path — build the equivalent in Laravel:
EnsureRouteCsrfToken (or extend the existing VerifyCsrfToken deny-list with a route-scoped allow-list). Resolve the route, read $route->getAction('csrf_token') or a csrf middleware alias; if present, pull the token from the configured field/header and validate with hash_equals against session()->token().->middleware('csrf:strict') or ->withTrashed()-style custom method ->csrf(). Prefer native middleware aliases over custom route action keys for discoverability and for route:list visibility.@csrfLink(), csrf_url()) that appends the token, replacing the Symfony router-decoration mechanism. Do not globally rewrite every generated URL — that leaks tokens into referrers, logs, and browser history for routes that don't need it.intention option with a signed payload (url, intention, expiry) to prevent cross-route token replay. Symfony's is session-keyed; ours should be explicitly scoped.X-XSRF-TOKEN header and add explicit Origin/Referer checks. Sanctum already covers SPAs; do not duplicate.Compatibility: Target PHP 8.1+ on a supported Laravel (10/11/12). No Symfony packages introduced. No lockfile change. The only shared artifact with the source repo is the idea — MIT license permits reimplementation; we should attribute the inspiration in the design doc for provenance, not vendor the code.
Sequencing (2 sprints, small):
Explicit non-path: installing the bundle, bridging Symfony's kernel, or writing a Laravel adapter around GenedysCsrfRouteBundle. The engineering cost of the adapter exceeds the cost of a clean native implementation, and the adapter inherits the EOL framework and unmaintained-dependency risk without any offsetting benefit.
Maintenance: We own it — which is the point. The native middleware is ~80 lines plus tests, inside our codebase, on our supported framework version, reviewed by our security reviewers. Maintenance burden is near-zero and, critically, bounded: a framework upgrade touches our code, not an abandoned third-party bundle pinned to a dead Symfony major.
Support: With the source package there is no maintainer, no issue triage, and 0 dependents — meaning no community to shake out bugs or publish patches. Any defect becomes ours to find, diagnose, and fork. With the native implementation, the same is true but the blast radius is one file we wrote and understand, not a graph of Symfony 2/3-era transitive dependencies.
Scaling: The middleware approach scales linearly and cheaply: stateless per-request validation, single session read, hash_equals comparison. Costs are negligible relative to request handling. Watch one thing — if token URLs are appended to high-volume generated links (email templates, paginated lists, sitemaps), you get token sprawl into caches and logs. That's the reason to scope issuance narrowly rather than globally decorate the router the way the bundle does.
Failure modes to design against:
Referer headers and browser history. Mitigation: treat GET-protected actions as a stopgap; prefer converting them to POST/DELETE. Document the residual risk explicitly for audit.Cache-Control: no-store on token-bearing pages, and a friendly 419 recovery path (re-render, don't hard-fail).session()->regenerate() on auth events, which Laravel already does — verify it covers the token too.enabled: false toggle (as the bundle offers) is a foot-gun that lets CSRF protection be switched off in an incident and never switched back. Mitigation: no global kill switch; use per-route allow-listing with a documented exception register.Ramp-up: Minimal for a mid-level Laravel engineer — the middleware pattern is idiomatic and the test matrix is the only real work. Estimated 1–2 engineer-days. The security team's involvement is a doc review plus confirmation of scope (HTML-only vs XHR), which is the one decision that materially changes the design.
Bottom-line decision for the log: Reject enumag/csrf-route-bundle as a dependency — framework mismatch (Symfony 3, not Laravel), EOL platform, package-identity mismatch between repo and install name, and no stewardship (0 stars, 0 dependents, README-only maturity). Accept it as a validated design precedent for a native Laravel middleware covering non-form, state-mutating routes. Owner: platform team. Timeline: next hardening sprint. Success criteria: all identified non-form mutation paths token-validated, hash_equals comparison, intention-scoped tokens, no-store on token-bearing pages, and a documented exception register replacing any global on/off switch.
How can I help you explore Laravel packages today?