alkhwlani/xss-middleware
Laravel middleware that sanitizes incoming request data to help prevent XSS attacks. It filters user input and removes malicious HTML/scripts, adding a simple protection layer to your app without changing your existing validation flow.
composer require alkhwlani/xss-middleware
php artisan vendor:publish --provider="Alkhwlani\XssMiddleware\...ServiceProvider"
If no publish tag is documented, check the package's config/ directory in vendor/alkhwlani/xss-middleware first — that's where the tag lists, allowed HTML, and iframe/embed rules live.bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\Alkhwlani\XssMiddleware\...::class); // global
// or $middleware->web(append: [...]) for web-only
})
On Laravel 10 and below, add it to the $middleware (global) or $middlewareGroups['web'] array in app/Http/Kernel.php.web group and submit a comment/bio containing <script>alert(1)</script> or <iframe src="...">. Inspect $request->all() in a controller — it should arrive stripped. That's the entire value proposition: every controller downstream gets cleaned input without per-form code.web group, not global. API endpoints usually receive JSON and may be better served by dedicated request sanitization; running an HTML stripper over every JSON body is noise. If you do need APIs covered, verify it reads $request->json() and not only $request->request.FormRequest validation runs (it is if appended to the group), so validators see cleaned values. If you validate first and sanitize after, required|string checks can pass on payloads that later get mangled.{{ }} and e() are still your primary XSS control; treat this as defense-in-depth for stored content, especially if you ever render with {!! !!}.<p>, <b>, <a> via a WYSIWYG, configure the allowed-tag list in the package config or the middleware will strip legitimate markup. Do not attempt to "allow iframes" for embed widgets — sanitize them into a placeholder and re-render with a trusted oEmbed service client-side.<img src=x onerror=alert(1)>, javascript: hrefs, and nested <iframe>s, then assert the stored/returned value contains no onerror/javascript:/<iframe. This locks behavior if the package updates.SanitizesInput trait or a base FormRequest, call the package's sanitizer there as a fallback so behavior is identical whether traffic went through middleware or a queued job/console command.application/json bodies. A single-level array_map with strip_tags will miss payload[0][field]. Test with Postman/curl -H "Content-Type: application/json".<script> or %3Cscript%3E are decoded by browsers/servers at different stages. Verify the middleware decodes entities before stripping, or you will pass through a payload that a downstream html_entity_decode (or a careless template) turns back into executable script.composer update that adds new default strip rules (or new allowed tags) can silently change what user content looks like after deploy. Diff the vendor config against yours on upgrade.web group aren't penalized — or set the middleware to skip when Content-Length exceeds a threshold.app(YourMiddleware::class)->handle($request, fn($r) => $r)) to see precisely which tags/attributes get removed. Keep a Log::debug of the before/after diff in local development.SanitizeInput middleware that calls the parent and then applies app-specific rules (e.g., strip style attributes, normalize URLs). This keeps you upgrade-safe rather than editing vendor code.composer.json ("alkhwlani/xss-middleware": "^1.0") and cover it with your own tests; the maintenance burden is effectively yours.How can I help you explore Laravel packages today?