The best way to sanitize RichEditor in Laravel/Filament?
Filament says it's up to you to sanitize your wysiwyg, so here I am. https://filamentphp.com/docs/3.x/forms/fields/rich-editor#security
I'm building a Laravel + React application, the dashboard uses Filament RichEditor. The input I'm trying to sanitize looks like this (this is the actual text inside of wysiwyg):
1
2
3
<div>
<h1>Welcome to the Test Page</h1>
<p>This is a <b>bold</b> paragraph with an <a href="https://example.com" onclick="alert('Clicked!')">external link</a>.</p>
<!-- Inline script injection -->
<script>alert('This script should be removed!');</script>
<!-- Malicious iframe -->
<iframe src="https://example.com" width="300" height="200"></iframe>
<!-- On-event handlers -->
<img src="https://via.placeholder.com/150" onerror="alert('Image load error!')" />
<!-- Inline styles -->
<p style="color: red; position: fixed; top: 0; left: 0; width: 100%; background: yellow;"> This text has dangerous inline styles like fixed positioning. </p>
<!-- Hidden input field -->
<input type="hidden" value="Sensitive Data" />
<!-- SVG with embedded script -->
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="blue" />
<script>alert('This SVG script should also be removed!');</script>
</svg>
<!-- XSS payload -->
<p><img src="x" onerror="javascript:alert('XSS payload executed!')" /></p>
</div>
onerror="javascript:alert('XSS payload executed!')"
<ul><li>1</li><li>2</li><li>3</li></ul> <p> onerror="javascript:alert('XSS payload executed!')" </p> <p><div><br> <h1>Welcome to the Test Page</h1><br> <p>This is a <b>bold</b> paragraph with an <a href="https://example.com" onclick="alert('Clicked!')">external link</a>.</p><br> <!-- Inline script injection --><br> <script>alert('This script should be removed!');</script><br> <!-- Malicious iframe --><br> <iframe src="https://example.com" width="300" height="200"></iframe><br> <!-- On-event handlers --><br> <img src="https://via.placeholder.com/150" onerror="alert('Image load error!')" /><br> <!-- Inline styles --><br> <p style="color: red; position: fixed; top: 0; left: 0; width: 100%; background: yellow;"> This text has dangerous inline styles like fixed positioning. </p><br> <!-- Hidden input field --><br> <input type="hidden" value="Sensitive Data" /><br> <!-- SVG with embedded script --><br> <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"><br> <rect width="100" height="100" fill="blue" /><br> <script>alert('This SVG script should also be removed!');</script><br> </svg><br> <!-- XSS payload --><br> <p><img src="x" onerror="javascript:alert('XSS payload executed!')" /></p><br></div><br><br></p>
I tried using https://github.com/mewebstudio/Purifier both ways:
Filament/Resources/Resource/CreateResource.php
use Mews\Purifier\Facades\Purifier;
// ..
protected function mutateFormDataBeforeSave(array $data): array
{
$data['description'] = Purifier::clean($data['description']);
// ..
return $data;
}
And model-level Model.php
use Mews\Purifier\Casts\CleanHtmlInput;
protected $casts = [
'description' => CleanHtmlInput::class,
];
Yet when I trigger saving it just, well, saves it as-is and I don't see even <script> removed, let alone other maliciousness. What am I doing wrong here? Any help would be much appreciated.
I have an option of just using https://github.com/cure53/DOMPurify, but I feel like sanitizing your inputs before they are saved is by far better than storing malicious wrappers.
UPD: On second thought, not sure if this is the intended behavior, but React's dangerouslySetInnerHTML outputs this code as simple text, alert() is not triggered, so maybe the way I input data in wysiwyg is wrong?
Please or to participate in this conversation.