Wednesday, January 19, 2011

A harmless SVG + XSLT curiousity

How do you execute code in a turing complete language via the <img> tag? Why, by combining an XSL transform into an SVG image of course!

I stumbled across this old file in my archives:

http://cevans-app.appspot.com/static/expensive_xsl_svg.html

If you run it e.g. in Chrome, it'll consume a load of CPU (and subsequently memory if you let it crank). I expect it'll do the same in any WebKit browser, and Opera's error message implies it has all the pieces to follow suit if I tweaked the file a bit.

It's not a significant security issue, but it's an interesting quirk. It works because SVG and XSL are both XML formats, and XSL can use a self-referential construct to operate on itself as the input document:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="#stylesheet"?>

If the XSL output XML is valid SVG syntax, then it will render. So you can probably pull some crazy tricks to generate a complicated SVG on the fly! My sample file doesn't get that far; it simply deliberately runs an expensive stylesheet transform with a large output.

If anyone wanted to play with this, there may be interesting issues with the unusual context the XSL is executing in. What if you used xsl:import or the document() XPath function? What origin is used for security checks?, etc.

2 comments:

Adam Barth said...

The loads should all fail in WebKit because SVG images don't have Frames, which means they're not connected to the loader machinery.

MarkGyver said...

This curiosity may be "harmless" on modern systems, but on my old system with only 1 GB RAM, Chrome quickly ate all available memory and swap, taking down the system with it. Even if it doesn't allow arbitrary code execution, I think that a 940 byte SVG-based denial of service attack can cause quite a bit of damage.

I guess the only real fix to resource-gobbling DoS attacks is having the browser put a resource limit on each tab and freeze it when it goes over. A popup would then let the user decide between killing the tab and letting it use more resources.