googlechromelabs/ise-web-security-bundle
A Symfony bundle from Google Chrome Labs that integrates ISE web security tooling into PHP applications. It helps developers configure browser security policies, apply security headers, and harden responses against common web threats with minimal setup and straightforward Symfony integration.
1.0.0 on a five-year-dormant, ten-star repo is exactly the shape of a supply-chain or maintainer-handoff event — read the diff before you require it.composer.json before assuming compatibility. The release notes describe features, not PHP/Symfony constraints. The old assessment's "no Symfony 6/7 support" claim needs re-verification: if v1.0 still targets Symfony 4/5, the bundle is a reference implementation for a Laravel app, not a dependency. In a Laravel codebase the realistic path is still: read the config tree and port the listener logic into app/Http/Middleware/SecurityHeaders.php (or adopt spatie/laravel-csp / bepsvpt/secure-headers and borrow only the semantics here).config/bundles.php → bin/console config:dump-reference ise_web_security. That command is now far more valuable than before — the release explicitly advertises a "comprehensive configuration process and tree," so the dump is the authoritative map of COOP, COEP, Fetch Metadata, and Trusted Types options.README.md → DependencyInjection/Configuration.php (now the real spec — four new feature families live here) → the header listener/subscriber → the Fetch Metadata request listener (new in v1.0, and it runs on kernel.request, not kernel.response, so it's in a different place than you'd expect) → Resources/config/services.*.X-Frame-Options + Referrer-Policy + X-Content-Type-Options on every response, with a per-request nonce surfaced to Twig/Blade. Only after that is stable should you layer on the v1.0 features — and one at a time, in Report-Only where the header supports it.report-only-ish staging behind a feature flag, (3) Fetch Metadata in log-only mode, (4) Trusted Types in Content-Security-Policy-Report-Only. Each one breaks a different class of third-party integration, and debugging two at a time is miserable.Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp is what actually gives you cross-origin isolation (SharedArrayBuffer, high-resolution timers, WASM threads). Enabling only one gets you the breakage without the capability. If you have OAuth popups or payment redirects that need window.opener, use same-origin-allow-popups rather than dropping COOP entirely.Sec-Fetch-Site / Sec-Fetch-Mode / Sec-Fetch-Dest and reject cross-site no-cors requests to state-changing or data-returning endpoints. In Laravel this belongs in middleware before your auth middleware, or at minimum before anything expensive. Always ship a permissive fallback for requests that send no Sec-Fetch-* headers at all (curl, older Safari, most API clients, health checks).require-trusted-types-for 'script' plus a trusted-types allowlist means every innerHTML, eval, document.write, and script.src assignment has to go through a policy or be rewritten. A tiny trusted-types default policy that passes strings through buys you time but defeats the XSS protection; use it only as a migration shim with a tracking ticket.report-uri/report-to at a small controller or a hosted collector first, watch for a week, then flip to enforcing. Trusted Types violations are only visible via reporting, so without this you're flying blind.config/security_headers.php with environment overrides, or a .env-driven toggle in the middleware.<script nonce=...>trustedTypes.createPolicy(...)</script>) that itself carries the nonce. Bind it as a singleton — Laravel's container singleton() or a scoped request attribute — anything regenerating it mid-request breaks inline scripts.spatie/laravel-csp, bepsvpt/secure-headers, nginx add_header, or a CDN's header transform, pick one writer per header. This gets worse with v1.0: COOP/COEP are also often set at the edge, and you will end up with duplicated or conflicting values.NOTICE, copy the listener/policy classes into src/Security/. Given the maintenance history, vendoring is still better than pinning.KernelBrowser (or Laravel's $this->get() + assertHeader) asserting header values, plus a test per new feature — a cross-origin no-cors request that should be rejected, and one that should pass. Unit-test the policy builder separately if you fork it.require-corp is the single most disruptive header in this release. Every cross-origin subresource — images, fonts, iframes, YouTube embeds, Stripe/ElevenLabs widgets, analytics pixels — must respond with Cross-Origin-Resource-Policy or be loaded CORS-enabled. Audit with DevTools Network filtered to failed requests before enabling globally. Recent Chromium also supports credentialless, which is often the pragmatic middle ground.window.opener will fail with same-origin. If you can't audit every flow, start with same-origin-allow-popups and tighten later.Sec-Fetch-* headers. If your rejection rule treats "missing" as "hostile," you'll 403 your own health checks. Decide explicitly: deny by default only on routes you know are browser-only.'unsafe-inline' — and Trusted Types inherits that problem. Adding a nonce silently breaks every inline handler and third-party snippet. Same spec behaviour as before, just with a bigger blast radius once a Trusted Types policy is in play.set() replaces; false as the third argument appends and produces Header: a, b — a classic malformed-CSP source. Strip headers your web server or CDN already sets; duplicates are especially hard to spot across COOP/COEP because the browser just ignores the ambiguity.config:dump-reference output is long enough to be misleading if truncated — dump to a file and diff it against the README, which will lag behind. getAlias() is still the source of truth for the YAML root key.curl -sI the route; DevTools Console for CSP/Trusted Types violations; DevTools Network for COEP-blocked subresources; listen for securitypolicyviolation during development. Verify the Sec-Fetch-* values your app actually receives with a temporary log line — assumptions about what browsers send are usually wrong.decorates: <bundle service id> to wrap the policy builder or listener, or in Laravel wrap the middleware class. If v1.0 has no clean seam for the header you need, that's a signal to vendor the code.NOTICE obligations changed. Assume you are the maintainer the moment you install it — pin the exact version and put a calendar reminder to revisit.How can I help you explore Laravel packages today?