Blade's default {{ $variable }} syntax automatically escapes output as an XSS protection — genuinely rendering a string as raw HTML (rather than escaped, literal text) needs the unescaped {!! !!} syntax instead, and understanding the security trade-off that comes with it matters more than the syntax itself.
The default: escaped output
{{ $post->title }}
If $post->title contained , this renders as the literal visible text of that string, not an executed script — this automatic escaping is what protects against a common category of cross-site scripting (XSS) vulnerability by default, without any extra effort.
Rendering raw, unescaped HTML
{!! $post->body !!}
This renders $post->body's actual HTML tags as real markup — genuinely necessary for content that's supposed to contain formatting, like a rich-text editor's saved output, but this is exactly the syntax that reintroduces the XSS risk {{ }} protects against by default.
The critical rule: only use {!! !!} on content you trust
Rendering raw HTML from user-submitted input without sanitizing it first is a genuine, serious security vulnerability — {!! !!} is appropriate for content from a trusted source (your own CMS content, a rich-text field that's been through a proper sanitization step) and should never be used directly on unsanitized user input.
Sanitizing user-submitted HTML before rendering it raw
composer require mews/purifier
use Mews\Purifier\Facades\Purifier;
$cleanHtml = Purifier::clean($request->input('bio'));
$user->update(['bio' => $cleanHtml]);
{!! $user->bio !!}
A dedicated HTML sanitization library like HTMLPurifier (wrapped here by the mews/purifier package) strips dangerous tags and attributes (like or an onclick handler) while preserving legitimate formatting tags — running user-submitted HTML through this before storing or rendering it is the responsible approach, rather than trusting it as-is.
A safer alternative: Markdown instead of raw HTML
{!! Str::markdown($post->body) !!}
Accepting Markdown input from users (rather than raw HTML) and converting it to HTML server-side, using Laravel's built-in Str::markdown() helper, sidesteps the raw-HTML sanitization problem largely by construction — Markdown's syntax doesn't include a way to embed a tag in the first place.
Rendering trusted, static HTML fragments
{!! $trustedWidgetHtml !!}
For HTML that originates entirely from your own codebase (a hardcoded widget, a value built entirely from trusted constants, never from user input), {!! !!} is safe to use directly without any sanitization step — the risk is specifically about untrusted, external, or user-controllable content, not the unescaped syntax itself.