How to Escape XSS in Laravel Like a Pro (And Still Let Users Submit Rich Text)
Cross-Site Scripting (XSS) remains one of the most common and dangerous web vulnerabilities out there.
As Laravel developers, escaping XSS properly is non-negotiable.
But what if you want to allow users to submit rich text content — like blog posts, comments with formatting, or product descriptions — without breaking security?
In this post, I’ll show you how to escape XSS in Laravel the right way while still letting your users submit safe rich text.
⚠️ What Is XSS and Why Should You Care?
XSS occurs when an attacker injects malicious JavaScript into your site, which then runs in other users’ browsers. The consequences can range from stealing cookies and session hijacking to full account takeover.
Laravel’s Blade templating engine escapes output by default:
{{ $userInput }}
This means it converts special characters like <
, >
, &
into HTML entities — preventing malicious scripts from running.
🚫 Common Blade Mistake: Using {!! !!}
Without Care
To output raw HTML, many developers use Blade’s {!! $htmlContent !!}
directive. But if $htmlContent
contains untrusted user input, you open the door for XSS.
Never blindly trust raw HTML from users!
✅ Strategy 1: Use Laravel’s Built-in Escaping Wherever Possible
The best way to avoid XSS is to never output raw user input without escaping. That means:
{{ $user->name }}
will always be safe.
🖋️ Strategy 2: Let Users Submit Rich Text Safely Using Sanitizers
If your app requires rich text input (bold, italics, links, images), you must sanitize that input before saving or rendering.
Popular Sanitization Tools for Laravel
mewebstudio/purifier
A Laravel wrapper around HTMLPurifier, one of the best HTML sanitizers out there.HTMLPurifier
Removes malicious code while keeping allowed HTML tags intact.
Example usage with mewebstudio/purifier
:
composer require mewebstudio/purifier
Then, in your controller or model:
use Purifier;
$cleanHtml = Purifier::clean($request->input('content'));
Now, you can safely store and output $cleanHtml
with:
{!! $cleanHtml !!}
Because it’s been sanitized, the risk of XSS is greatly reduced.
🎯 Configure Allowed Tags and Attributes
You don’t want users to upload <script>
tags or inline event handlers (onclick
, onerror
).
Configure Purifier in config/purifier.php
or publish its config:
'HTML.SafeIframe' => true,
'HTML.Allowed' => 'p,b,strong,i,em,u,a[href|title],ul,ol,li,br,img[src|alt|width|height],blockquote',
'Attr.AllowedFrameTargets' => ['_blank'],
This allows only safe tags and attributes.
🧪 Strategy 3: Validate Inputs, Then Sanitize
Don’t skip validation before sanitization.
Example:
$request->validate([
'content' => 'required|string|max:5000',
]);
$cleanHtml = Purifier::clean($request->input('content'));
🚨 Bonus: Don’t Forget Other XSS Vectors
-
JavaScript in URLs: Sanitize or validate
href
attributes to avoidjavascript:
URLs. - CSS Injection: Restrict inline styles unless absolutely necessary.
-
Attribute Injection: Avoid allowing dangerous attributes like
onload
,style
, oronerror
.
🛠️ Strategy 4: Use Content Security Policy (CSP) Headers
Even with sanitization, adding CSP headers is a powerful additional layer.
Example middleware snippet:
public function handle($request, Closure $next)
{
$response = $next($request);
$response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self';");
return $response;
}
Packages like spatie/laravel-csp
help manage this easily.
🧩 TL;DR Best Practices for Escaping XSS & Handling Rich Text
- Always escape output by default (
{{ }}
) - Only use
{!! !!}
after sanitizing input - Use trusted sanitizers like
mewebstudio/purifier
- Validate input size and type before sanitizing
- Configure allowed HTML tags and attributes carefully
- Add CSP headers for extra defense
- Regularly audit and test your app for XSS
📘 Want to Learn More?
XSS is just one piece of the Laravel security puzzle.
In my book Bulletproof Laravel: Write Code That Hackers Hate, I dive deep into:
- Preventing XSS, CSRF, SQL injection
- Secure authentication and authorization
- Protecting file uploads and APIs
- Real-world security scenarios and checklists
If you want to truly master Laravel security, grab your copy here:
https://www.amazon.com/dp/B0FFNT7BMQ
👇 Your Turn
How do you handle rich text safely in Laravel?
Have you faced tricky XSS bugs? Share your tips or horror stories below!
Top comments (0)