SVG Uploads in WordPress: Why It's Blocked and How to Do It Safely
You've got a logo. It's an SVG. It'll look perfect at any size and weigh about 8KB.
WordPress won't let you upload it.
So you search for a fix, and within about thirty seconds you find a code snippet that promises to solve it. Four lines, drop it in functions.php, done.
Please don't.
Why WordPress blocks SVG in the first place
Most image formats are just pixel data. A JPEG can't do anything. It sits there being a picture.
An SVG isn't a picture. It's an XML document that a browser interprets — and that document can contain <script> tags, event handlers, external references, and embedded HTML.
Upload a malicious SVG, get someone to open it, and that script runs in their browser with their session. If that someone is an administrator, you've just handed over your site.
This isn't theoretical, and it isn't rare. It's why WordPress core has refused SVG uploads for years despite constant requests to allow them.
The snippet you found doesn't fix that
The popular workaround does exactly one thing: it tells WordPress that image/svg+xml is an allowed MIME type.
That's it. It adds the format to the allowlist. It doesn't inspect the file, doesn't strip anything dangerous, and doesn't check who's uploading.
It's not a security measure. It's the removal of one.
And here's the part people underestimate: it applies to everyone who can upload a file. If you run a multi-author site, accept guest contributions, or have a WooCommerce store with vendor accounts, you've just given every one of those users a script execution vector.
What a safe implementation actually needs
Three layers, and most "SVG support" plugins only do one of them.
Validation — reject the file before you ever process it. Check the real MIME type from the file bytes rather than trusting the extension. Block double extensions like payload.php.svg. Cap file size, DOM node count, and declared dimensions, because an SVG with a million nodes is a denial-of-service payload dressed as a logo.
Sanitization — parse the XML and strip anything not on a strict allowlist. Remove scripts, event handlers, external references. Then scan the cleaned output again as a string, because DOM sanitization alone has been bypassed before.
Containment — assume something gets through anyway. Content Security Policy headers, X-Content-Type-Options: nosniff, and X-Frame-Options limit what a surviving payload can do.
The gap almost everyone misses
Here's the one that catches even careful implementations.
Your plugin adds security headers when WordPress serves an SVG attachment page. Good. But what happens when someone hits the file directly?
https://yoursite.com/wp-content/uploads/2026/09/logo.svg
That request never touches WordPress. Your web server hands over the file directly. Every PHP-layer security header you configured is simply never sent.
Direct links, CDN pulls, hotlinks from other sites — none of them are protected by anything living inside WordPress. Closing that gap requires configuration at the server level, in Apache or Nginx, not in PHP.
How CodePros SVG Secure Support handles it
CodePros SVG Secure Support implements all three layers, plus the server-level piece most plugins skip.
Five validation checks run before a file is accepted: extension, real MIME type from file bytes, file size, DOM node count, and declared dimensions. Fail any one and the upload is rejected outright with a clear error.
Sanitization runs through enshrined/svg-sanitize — the same battle-tested library most serious implementations use — with custom tag and attribute allowlists. All external URLs get stripped. Then a final string-level scan looks for javascript:, <script, inline event handlers, and CSS expression(). Anything that survives the DOM pass and trips that scan means the whole upload is rejected, not cleaned.
Security headers get added on SVG attachment pages: configurable CSP, nosniff, and SAMEORIGIN.
Server config snippets ship with the plugin — ready-to-paste .htaccess and Nginx blocks for your uploads directory. These close the direct-access gap, block PHP execution in uploads entirely, and force the correct MIME type so your CSP rules actually apply.
Role-based access means SVG upload is an administrator-only capability by default. You can extend it to specific roles, but you're doing it deliberately rather than by accident.
Every event is logged. Blocked uploads, stripped tags, suspicious payloads — all filterable in the admin, with configurable retention. If something odd happens, you'll have a record of it.
Two honest caveats
It needs Composer. You have to run composer install in the plugin directory before activating, because the sanitization library is a dependency rather than bundled code. On managed hosting without SSH access, that's a real obstacle. Worth checking before you commit.
Multisite isn't tested. Network activation isn't supported yet. If you're on multisite, wait.
Also, and this matters: no sanitization approach can promise absolute safety. This pipeline covers every known SVG attack vector and follows what security researchers recommend. "Known" is doing real work in that sentence, and anyone claiming otherwise about any tool is selling you something.
Should you even use SVG?
Fair question. For logos, icons, and simple illustrations, yes — they scale perfectly, they're tiny, and they stay crisp on every display.
For photographs and complex imagery, no. That's what WebP and proper image optimization are for, and trying to force photographic content into SVG produces enormous files that defeat the point entirely.
Use each format for what it's good at. SVG for vector, WebP for raster. One exception worth knowing: email clients don't reliably render SVG, so keep logos in your order emails as PNG.
Do it properly or don't do it
If you only need to upload one logo, ask your developer to place it via FTP and skip the plugin entirely. Fewer moving parts.
If your team needs to upload SVGs regularly, don't paste a snippet into functions.php and hope. Enabling SVG uploads is a security decision, and it deserves an actual implementation rather than a workaround.
Continue Reading
- News WordPress 7.1.2: Update Your Store Today. Here's What It Won't Fix. →
- Speed WordPress Image Optimization: Why Your Site Is Slow and How to Fix It →
- Checkout WooCommerce Address Autocomplete: Stop Losing Orders at Checkout →
- Email WooCommerce Order Emails Look Terrible. Here's How to Fix Them. →
- Compare Which Code Pros Plugin Do You Need? →