silksh/security-bundle
A security bundle for Laravel that bundles common hardening tools and sensible defaults to help protect your application. Note: this package has no stars or score yet and appears to be early-stage or unmaintained, so review the source before using it in production.
Framework reality check before anything else: silksh/security-bundle is a Symfony bundle, not a Laravel package. There is no composer.json extra.laravel.providers entry, no ServiceProvider, no publishable config/security_bundle.php, no facades, and no php artisan vendor:publish. If your app is on Laravel, composer require silksh/security-bundle may resolve but will never boot — the Bundle subclass, its DependencyInjection\*Extension config tree, and any compiler passes have no host in the Laravel kernel. A Laravel developer's day-to-day use of this package is therefore not "install and configure" — it is mining it for patterns to reimplement in a small in-house package.
So the first thing to do is read the source, not run it:
README.md — may be absent or thin; do not assume docs exist.src/DependencyInjection/Configuration.php — this is the authoritative list of every knob the bundle exposes. This is your requirements document for whatever you reimplement.src/Resources/config/services.xml|yaml — shows which services the bundle wires and their tags (event subscribers, middleware).src/ middleware/subscriber classes — the actual header and CSP logic.tests/ — if absent, treat every behavior as unverified.composer require silksh/security-bundle, register the bundle in config/bundles.php (confirm the FQCN from src/ — the namespace may not match the vendor name), and confirm whether a Flex recipe exists (assume it does not; register manually).X-Frame-Options, Referrer-Policy, X-Content-Type-Options, Permissions-Policy) applied via a global middleware. It is low-risk, immediately observable in a browser devtools network tab, and replaces hand-rolled header code you'd otherwise write inline in Kernel-adjacent middleware anyway.The realistic day-to-day leverage for a Laravel developer is a pattern-to-package port: extract the ideas from the Symfony source, wrap them in a first-party Laravel package (app/Support/Security/ or a private Composer package) with a ServiceProvider, a publishable config, and tests.
Pattern 1 — Headers as a single middleware, config-driven.
Reimplement as one SecurityHeaders middleware that reads from config/security.php and appends headers to the response. Keep the config key shape close to the bundle's Configuration.php so the settings remain familiar to anyone reading the Symfony source. Register it in the web and api middleware groups (or globally) via bootstrap/app.php in Laravel 11+:
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\App\Http\Middleware\SecurityHeaders::class);
})
Keep HSTS off in local/testing — sending Strict-Transport-Security over plain HTTP poisons browsers for that host and is painful to undo during development.
Pattern 2 — CSP with a per-request nonce.
The bundle supports CSP nonces; port that as a middleware that generates base64_encode(random_bytes(16)), stores it on the request (or in a scoped container binding), and exposes it to Blade via @cspNonce or a shared view variable. The middleware then sets Content-Security-Policy on the way out. Critically, keep a report-only mode in config so you can roll out without breaking inline scripts and third-party widgets. Do not enable script-src 'unsafe-inline' as a "temporary" fix — it defeats the point and never gets removed.
Pattern 3 — Input sanitization helpers as opt-in, not global.
If the bundle ships sanitization/validation helpers, port them as explicit Form Requests or a dedicated Sanitized value object, not as a middleware that mutates the whole request. Silent global mutation is a debugging nightmare and surprises other developers. Validation belongs in Form Requests; sanitization belongs at the boundary where untrusted data is consumed (rendering, SQL via bindings, shell out — just don't).
Pattern 4 — Voters/access-control helpers → Laravel Gates and Policies.
If the Symfony source includes access-decision logic, its Laravel equivalent is Gate::define and Policy classes. Do not port Symfony's voter system; the concepts are equivalent but the APIs are incompatible and you'll fight the framework.
Integration tips:
SecurityHeadersProvider) so a header set can be swapped per environment or per route group without touching middleware code.security.headers.enabled) so you can canary the change and disable it without a deploy if something breaks.->middleware(['security.headers:strict']) or a config map keyed by route name.Do not composer require this into a Laravel app "to try it." A security dependency that installs but silently does nothing is the single most dangerous failure mode here — your team will believe protection exists when it doesn't. If you require it for source inspection, require it in a throwaway scratch app, not the production codebase.
Composer resolution pain is a stop signal. A Symfony bundle constraining symfony/framework-bundle or a specific symfony/security-* major version can deadlock Composer against Laravel's pinned Symfony component set (Laravel pulls in symfony/http-foundation, symfony/console, symfony/process, etc.). If resolution fights you, do not --ignore-platform-reqs past it — that's a sign the dependency doesn't belong.
Maintenance is now yours. Zero dependents means no upstream patch pressure, no community forks to lean on, and no signal when the maintainer goes dormant. If you vendor any of it, name an owner, pin a fork, and log it in your dependency-review process — otherwise a composer update in a year will surface something unpatched with no obvious path to a fix.
Namespace ≠ vendor name. If you do end up on Symfony and registering the bundle, verify the actual FQCN from src/ before writing it into config/bundles.php. Vendors occasionally ship bundles whose registered class namespace doesn't match the composer.json package name, and a typo there gives you a confusing "class not found" at boot.
CSP nonce pitfalls when porting: if you cache rendered HTML (full-page cache, view cache, Cache::remember around a Blade render), the nonce baked into the cached fragment goes stale and CSP blocks everything on the next request. Either exclude CSP-nonce-bearing pages from full-page cache or regenerate nonces via a client-side strategy you've deliberately chosen.
Debugging tip: the Symfony bundle's Configuration.php is the closest thing to documentation it has. Read it first. If you're porting, mirror its default values in your Laravel config with comments citing the original — it makes future security reviews far easier and documents why a value was chosen.
Extension point to preserve in your port: the roll-out story. Whatever you build should support report-only mode for CSP, per-environment toggles for HSTS, and a way to add a custom header without touching middleware code. That flexibility is what makes the pattern survive contact with a real app.
Bottom line for a Laravel developer: the honest day-to-day answer is "read it, don't depend on it." Spend half a day reading the source, extract the header and CSP patterns, and reimplement them in ~100 lines of first-party Laravel middleware. You get the ideas at near-zero supply-chain cost, with a Laravel-native API and one owner (you) who can actually maintain it.
How can I help you explore Laravel packages today?