enshrined/svg-sanitize
PHP SVG/XML sanitizer inspired by DOMPurify. Clean untrusted SVGs with a simple sanitize() call, optional custom tag/attribute whitelists, remote reference stripping to prevent leaks, issue reporting, and output minification. Returns clean XML or false on parse errors.
Install via Composer with composer require enshrined/svg-sanitize. Start by sanitizing a raw SVG string: instantiate enshrined\svgSanitize\Sanitizer, call sanitize($svg), and handle the result. A false return means parsing failed—inspect issues with getXmlIssues(). Use the CLI scanner (php svg-scanner.php path/to/file.svg) for quick local validation during development. The demo is invaluable for visualizing what gets stripped (e.g., <script>, onload, xlink:href to external URLs).
Rule::forbiddenExtensions() or custom Rule::_svgSanitize(). Sanitize before storage:
$svgContent = $request->file('logo')->get();
$sanitizer = new Sanitizer();
$cleanSvg = $sanitizer->sanitize($svgContent);
if ($cleanSvg === false) {
// Log issues, reject upload
logger()->warning('SVG sanitization failed', $sanitizer->getXmlIssues());
return response()->json(['error' => 'Invalid SVG'], 422);
}
Storage::put('logos/safe-logo.svg', $cleanSvg);
TagInterface/AttributeInterface to permit <use> with href only when pointing to local IDs (e.g., reject xlink:href="https://..." while allowing xlink:href="#icon-arrow"):
$sanitizer->setAllowedTags([SvgTags::class]); // Only <svg>, <path>, <g>, <use>, etc.
$sanitizer->setAllowedAttrs([SvgAttrs::class]); // Filter xlink:href in CustomAttrs
removeRemoteReferences(true) to block external assets and prevent SSRF. Combine with minify(true) in production to reduce storage/bandwidth.getXmlIssues() to Sentry or Slack for real-time alerts. Include SVG source context (e.g., user_id, upload path) in logs.xlink:Href (uppercase) fail silently; 0.22+ normalizes case, but legacy uploads may still break—always log getXmlIssues() and test with edge-case SVGs (e.g., mixed-case attributes).&) cause XML parsing to fail before sanitization—enable libxml_use_internal_errors(true) and capture libxml_get_errors() before sanitize() to get human-readable diagnostics.<rect width="0"/> is "clean" but invisible). Validate rendering separately in staging.Sanitizer instances (e.g., bind as singleton in AppServiceProvider). Avoid calling sanitize() on non-SVG files—check MIME type first (finfo_file($file, FILEINFO_MIME_TYPE) === 'image/svg+xml').How can I help you explore Laravel packages today?