Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Xss Filter Laravel Package

masterro/laravel-xss-filter

A Laravel package for filtering XSS from user input. It offers configurable sanitization and middleware to clean request data, helping protect your application from cross-site scripting attacks with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with Composer:

    composer require masterro/laravel-xss-filter
    
  • Publish the config file (check the README for the exact provider or tag in your version):

    php artisan vendor:publish --provider="MasterRO\LaravelXssFilter\Providers\LaravelXssFilterServiceProvider"
    
  • Open config/xss-filter.php first. This is where you define the HTML you want to keep:

    • allowed_tags: e.g. p, a, strong, em, ul, ol, li, blockquote, code, pre, br, img.
    • allowed_attributes: usually per-tag, e.g. a => ['href', 'title'], img => ['src', 'alt', 'title', 'width', 'height'].
  • Register the middleware. For a traditional server-rendered app, add it to the web group so all form input is filtered:

    // app/Http/Kernel.php
    protected $middlewareGroups = [
        'web' => [
            // ...
            \MasterRO\LaravelXssFilter\Middleware\XssFilter::class,
        ],
    ];
    

    Or register an alias and apply it only where needed:

    protected $routeMiddleware = [
        'xss' => \MasterRO\LaravelXssFilter\Middleware\XssFilter::class,
    ];
    
    Route::post('/posts', [PostController::class, 'store'])->middleware('xss');
    
  • First use case: a blog post or comment form with a WYSIWYG editor. Submit a payload like:

    <script>alert(1)</script><p>Hello <strong>world</strong></p>
    

    After the middleware runs, $request->input('body') should be:

    <p>Hello <strong>world</strong></p>
    
  • Test the filter directly in Tinker or a unit test if the package exposes its filter service/facade, e.g. XssFilter::clean($payload). Check the package README for the exact class or facade name in your version.

Implementation Patterns

  • Global middleware on the web group: simplest for classic Laravel form apps. Every request input is sanitized before it reaches your controller, so you can treat $request->input() as “XSS-filtered but HTML-preserving” for fields that match your allowlist.

  • Route-specific middleware: better when only some endpoints accept HTML. Apply xss to post/comment/description routes, and leave login, password reset, search, and API endpoints untouched. This avoids mangling passwords or code snippets that legitimately contain <, >, or &.

  • FormRequest + targeted filtering: validate first, then filter only rich-text fields. If the package’s middleware is too broad, use its filter service in passedValidation() or the controller:

    public function store(StorePostRequest $request)
    {
        $data = $request->validated();
        $data['body'] = XssFilter::clean($data['body']);
    
        Post::create($data);
    }
    

    This keeps passwords, emails, and structured JSON untouched.

  • Admin vs. public allowlists: public comments usually need a strict set (p, a, strong, em, ul, li). Admin WYSIWYG content may need images, tables, headings, etc. Because the package config is global, either:

    • keep one conservative allowlist and use a custom filter service for admin content, or
    • create a second middleware/service instance with a different HTMLPurifier configuration.
  • API/JSON endpoints: be careful. Middleware that calls $request->merge($cleaned) on all input may recursively filter arrays, but verify nested JSON behavior. For APIs that accept rich text, filter only the specific string fields. For APIs that accept binary/base64/signed payloads, do not apply the middleware at all.

  • Blade output: filtering input is defense-in-depth, not a replacement for output escaping. Continue using {{ }} for normal text and reserve {!! !!} for fields you have explicitly filtered and trust. If you both filter on input and escape on output, users may see HTML entities like &lt;p&gt; — decide where filtering happens.

  • Testing pattern: add a feature test that posts a known payload and asserts:

    • <script> is gone,
    • safe tags remain,
    • onerror, onclick, and javascript: URLs are removed.
    $response = $this->post('/posts', [
        'body' => '<script>alert(1)</script><p>Hello <strong>world</strong></p>',
    ]);
    
    $this->assertDatabaseMissing('posts', ['body' => '<script>alert(1)</script>']);
    $this->assertStringContainsString('<strong>world</strong>', Post::first()->body);
    
  • Layered security: pair the package with validation, output escaping, CSP headers, and CSRF protection. Input filtering alone does not protect against stored XSS if templates render raw HTML carelessly.

Gotchas and Tips

  • It can alter legitimate non-HTML input. Passwords, API keys, mathematical expressions, and code snippets may contain < or &. Do not apply the middleware globally if your app has such fields — use route-specific middleware or filter only rich-text fields.

  • HTMLPurifier can be slow. If the package uses HTMLPurifier under the hood, filtering every request has a cost. Apply it only to endpoints that accept HTML, and cache configuration in production.

  • Config cache quirks. After editing config/xss-filter.php, run:

    php artisan config:clear
    

    In production, rebuild with php artisan config:cache. Otherwise your new allowed tags may not take effect.

  • Allowed attributes are per-tag. Do not allow style, on*, or arbitrary attributes. Keep the allowlist minimal. Test href="javascript:alert(1)" and img src="x" onerror="alert(1)" explicitly.

  • Protocol filtering matters. HTMLPurifier usually blocks javascript: URLs, but if you customize attributes or bypass the purifier, you can reintroduce the vulnerability. Verify mailto:, tel:, and relative URLs still work for your use case.

  • Nested arrays and JSON. Confirm whether the middleware recursively cleans nested input. If not, write a small recursive helper:

    function cleanInput(array $input): array
    {
        return array_map(function ($value) {
            return is_array($value) ? cleanInput($value) : XssFilter::clean($value);
        }, $input);
    }
    
  • File uploads are out of scope. The package filters input strings, not uploaded files. Validate MIME types, extensions, and storage paths separately.

  • Double-escaping confusion. If you filter on input and also escape on output with {{ }}, stored HTML may display as entities. If you render filtered HTML with {!! !!}, make sure the field is definitely filtered and that your allowlist is strict.

  • Debugging. Test payloads directly in Tinker or a small unit test. Compare $request->all() before and after the middleware. If the package exposes a clean() method, call it directly with representative payloads rather than debugging through a full HTTP request.

  • Extension point. The published config is the main extension point. For per-form rules, create a custom middleware or service that instantiates the filter with a different allowed-tag set, rather than editing the global config for one edge case.

  • Maintenance and pinning. This is a small package (41 stars). Pin the version in composer.json, review the changelog on upgrade, and keep your own XSS tests so you can detect behavior changes. The 2026 release date suggests it is maintained, but community support is limited compared with larger security packages.

  • Do not rely on it alone. Treat it as one layer. Validate input, escape output, use CSP, and review any place where you render user HTML with {!! !!}.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus