Enabling uploads of SVG files in WordPress is quite easy, and there is a tonne of posts on the Interwebs explaining how you do it. Usually along the lines of:

function add_svg_to_upload_mimes( $upload_mimes ) {
	$upload_mimes['svg'] = 'image/svg+xml';
	$upload_mimes['svgz'] = 'image/svg+xml';
	return $upload_mimes;
}
add_filter( 'upload_mimes', 'add_svg_to_upload_mimes', 10, 1 );

And that’s pretty much it.

Except it is not.

Why WordPress doesn’t allow uploading SVGs

WordPress is an excellent CMS “out of the box”, very easy to use and “just works” for the large majority of users. So why aren’t SVGs allowed in the first place? Why do we have to jump through hoops to make SVGs work?

Short answer: SVG files are extremely unsecure.

Long answer: SVG support in WordPress have been discussed in trac ticket #24251 for a very long time, and probably will be discussed further for a very long time.

[bjornad]

Contrary to what many people believe, SVG is not an image format. It is a document format. Unfortunately for us who just want vector graphics on the web, it is also quite a powerful and flexible document format. As an example, SVG files allows JavaScript to be embedded and SVG readers, i.e. your browser, are expected to execute it.

This is a valid SVG file picturing a red circle:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="18.4" r="18.4" fill="#f00" />
<script>
 alert( 'Well, hello there!' );
</script>
</svg>

Notice anything funny with it? Try saving it as a file on your computer and open it in a browser. The result might look something like this:

Browser window showing an alert box with the text “Well, Hello There!”

Looks like we got more than just an innocent image with a red circle. This would be very easy to exploit in a XSS attack.

Q: So why can’t we just run the SVG through a KSES filter that removes the script elements? A: Because XSS is just the simplest problem. Since SVG is XML based, it opens for a plethora of problems, e.g. XXE, Billion laughs, quadratic blowup etc.

In the above mentioned trac ticked Chris Christoff (chriscct7) explains:

SVG file security isn’t some obscure bug. There’s multiple, well known SVG vulnerabilities. It isn’t a theory, an obscurity, or an unknown. There are well over 8,000 logged CVE’s that have to do with all sorts of fun and obscure SVG file security vulnerabilities.

Further on, Ian Dunn, points out that an SVG sanitizer might not be so easy to write:

Mario Heiderich, one of the researchers who popularized the security issues, tried writing a sanitizer and found it to be harder than even he imagined.

The thing is that “security people who have vast background in web attacks and XSS” have written DOMPurify – “a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG”. It is, however, written in JavaScript for the client side, so it’s probably not something we easily can include in WordPress.

Anyhow, Daryll Doyle (enshrined), used DOMPurify as a basis, ported parts of it to PHP and released the library svg-sanitizer. He has also been kind enough to release the WordPress plugin Safe SVG that both enables SVG uploads and filter all uploaded SVG files through svg-sanitizer. Daryll is very clear on the fact that this is mostly to serve as a proof of concept, but it does seem to be good at sanitizing several attack vectors.

Chris Christoff also points out:

If WordPress were to ever allow SVGs, the sanitize library would not only need to work well, it would also need to be thoroughly tested, in large scale production environments. Literally by design, SVGs are designed to be insecure.

[…]

The second something like SVGs were to get into WordPress core, our library would be scrutinized, poked and prodded for security holes.

Remember that WordPress powers more than a quarter of all websites, so security isn’t something we can take lightly.

[bjornad]

– Blah, blah, I still want SVG files

If you understand the risks, you know better than allowing users you don’t trust fully to upload SVG files. By “trust fully” I mean users who also understand the risks and know how to avoid them. You might have users who don’t have bad intentions, but who are willing to upload an SVG file they got from someone else.

But if you do trust all your users or simply have to accept the risk, please do not use a code snippet like the one at the beginning of this article. Please use the plugin Safe SVG instead. It will at least do some scrutinizing.