SVG Security & Performance
When to Use
You're working with SVG icons and need to understand security implications and optimization techniques.
Decision
| Risk level | Source | Mitigation |
|---|---|---|
| Low | Local SVG files (theme/module) | SVG extractor sanitizes automatically |
| Medium | Sprite files (local) | Sprite extractor validates structure |
| High | Remote SVG URLs | Never use SVG extractor, use Path with CSP |
| Critical | User-uploaded SVG | Never use Icon API, use Media with validation |
Pattern
Secure SVG handling:
# ✅ Safe - Local SVG files
safe_pack:
extractor: svg
config:
sources:
- icons/{icon_id}.svg # Local only, sanitized by extractor
# ⚠️ Caution - Remote sprites (sprite extractor allows)
remote_sprite:
extractor: svg_sprite
config:
sources:
- https://trusted-cdn.example.com/sprite.svg # Validate domain
# ❌ Never - User-uploaded SVG via Icon API
# Use Media entity with SVG sanitization module instead
SVG sanitization in extractor:
// SVG extractor automatically sanitizes content
// Removes:
// - <script> tags
// - Event handlers (onclick, onload, etc.)
// - External references (xlink:href to external domains)
// - Embedded stylesheets with expressions
Optimize SVG sources:
# Install SVGO
npm install -g svgo
# Optimize all icons
svgo --folder icons/ --config svgo.config.js
# svgo.config.js
module.exports = {
plugins: [
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeEditorsNSData',
'cleanupAttrs',
'mergeStyles',
'inlineStyles',
'minifyStyles',
'cleanupIds',
'removeUselessDefs',
'cleanupNumericValues',
'convertColors',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeViewBox', // Remove if you control viewBox in template
'cleanupEnableBackground',
'removeHiddenElems',
'removeEmptyText',
'convertShapeToPath',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
'convertPathData',
'convertTransform',
'removeEmptyAttrs',
'removeEmptyContainers',
'mergePaths',
'removeUnusedNS',
'sortAttrs',
'removeTitle',
'removeDesc',
]
};
Content Security Policy for remote sprites:
// In SecurityHeadersSubscriber or similar
$response->headers->set('Content-Security-Policy',
"default-src 'self'; img-src 'self' https://trusted-cdn.example.com;"
);
Reference: /core/lib/Drupal/Core/Theme/Icon/Plugin/IconExtractor/SvgExtractor.php
Common Mistakes
- Wrong: Trusting user-uploaded SVG → Right: Never use Icon API for user content, use Media with SVG sanitizer
- Wrong: No CSP for remote sprites → Right: Restrict domains via Content-Security-Policy header
- Wrong: Not optimizing SVG sources → Right: Run svgo before deployment for smaller file sizes
- Wrong: Including complex SVG features → Right: Remove animations, scripts, external references
- Wrong: Storing sensitive data in SVG metadata → Right: SVGO removes metadata, but verify manually