Using Javascript code inside of an SVG file and then uploading it to a website that accepts SVG files & does not sanitize their content.
This is how a ton of websites fail and are directly exposed to this XSS vulnerability.
You have two choices:
- Do not allow users to upload SVG files
- Allow users to upload SVG files, but use an SVG cleaner on upload
Table of Contents
How is this exploit working?
Any type of JS code can be added inside an SVG file.
You upload the SVG image file to a website that allows SVG file uploads and does not clean them.
If you manage to get the URL of that uploaded SVG file & that file is saved in the same domain of the main website, the exploit is complete.
You can write malicious JS code to dump cookies (for example) wherever you want to.
You can then simply send the SVG URL to any user of that particular website which you are also a part of, and if that user opens it the JS code will execute.
How to fix it?
The fix to the SVG XSS vulnerability is simple.
Let’s assume that you still want your users to be able to upload SVG files.
In that case, you would need to use an SVG cleaner before you store the uploaded file.
We’re going to use an SVG cleaner library: daryll/svg-sanitizer
Code example
I’m going to write an extremely simple example to illustrate how this can be solved with ease.
First off, make sure that you download the SVG-sanitizer code from the above SVG cleaner library.
If you use composer, simply require the library into your code.
Let’s say you have the following upload processing code
<?php /* Load the autoload file from vendor */ require_once './vendor/autoload.php'; /* Check for form submission */ if(!empty($_POST)) { $file_extension = explode('.', $_FILES['image']['name']); $file_extension = mb_strtolower(end($file_extension)); $file_temp = $_FILES['image']['tmp_name']; /* THIS IS JUST AN EXAMPLE */ /* Here you typically do your form processing and validations */ /* Generate a new file name */ $file_new_name = md5(time(). rand()) . '.' . $file_extension; /* Upload the file */ move_uploaded_file($file_temp, realpath(__DIR__) . '/images/' . $file_new_name); } ?>
As mentioned in the code, this is just an example.
Normally, you have more validations and error checks before you upload the file.
Clean the SVG
Now, let’s clean the SVG file with the library that we have imported.
if($file_extension == 'svg') { $svg_sanitizer = new \enshrined\svgSanitize\Sanitizer(); $dirty_svg = file_get_contents($file_temp); $clean_svg = $svg_sanitizer->sanitize($dirty_svg); file_put_contents($file_temp, $clean_svg); }
This code will only run if the file extension is ‘svg’.
It will take the temporary file which was uploaded.
Then put it through the SVG Cleaner.
And save it back into the initial temporary file.
Final code example
The full PHP code would look something like this:
<?php require_once './vendor/autoload.php'; /* Check for form submission */ if(!empty($_POST)) { $file_extension = explode('.', $_FILES['image']['name']); $file_extension = mb_strtolower(end($file_extension)); $file_temp = $_FILES['image']['tmp_name']; /* THIS IS JUST AN EXAMPLE */ /* Here you typically do your form processing and validations */ if($file_extension == 'svg') { $svg_sanitizer = new \enshrined\svgSanitize\Sanitizer(); $dirty_svg = file_get_contents($file_temp); $clean_svg = $svg_sanitizer->sanitize($dirty_svg); file_put_contents($file_temp, $clean_svg); } $file_new_name = md5(time(). rand()) . '.' . $file_extension; /* Upload the original */ move_uploaded_file($file_temp, realpath(__DIR__) . '/images/' . $file_new_name); } ?>
Video tutorial
I have also recorded a video tutorial on how you can implement this library and fix this XSS SVG exploit in under 5 minutes.
Conclusion
Please, make sure that you clean all the SVG file uploads, as otherwise, you are exposing yourself to risk for no reason.
Hope you’ve found this useful, take care!