This is really not what you ever want to see on your own site:
It’s a JavaScript prompt and no, it’s not meant to be there. Someone had successfully mounted an XSS attack against this very website!
Now I’ve written a lot about XSS, I’ve authored multiple Pluralsight courses that talk about it in detail and I’ve run many workshops on the topic teaching others the very mechanics of how cross site scripting works. Yet here we are – XSS on my own blog.
Fortunately, this was discovered by friend and fellow security MVP Alun Jones who you can hear in the video above. If anyone’s going to find a security flaw in my things, I want it to be Alun! But is it really “my” thing where the flaw is? I asked Alun to capture some more detail with the full expectation of sharing it publicly and he went well above and beyond by recording that video. He also captured a nice little Fiddler trace for me which means that now we can dissect it together and explore exactly how this happened. The URL from the screen above was this one: http://www.troyhunt.com/?”-prompt()-“
I actually worked out the mechanics of it in reverse, that is I searched for “prompt” in the Fiddler trace, found where it was rendered into the response and then worked out what things called that things and then what called those things and so on until I got back to the source. So it makes more sense, let me describe the problem here chronologically:
- A request is made to my site with this query string ?"-prompt()-"
- My site doesn’t do anything with the query string, but it does embed Developer Media’s (my ad provider) script.
- That then initiates three requests (once for each ad placeholder on the site) to Google’s DoubleClick ad network. When it does this, the referrer is also passed so that DoubleClick now has the full URL including the XSS payload.
- DoubleClick then does a great big document.write which renders an iframe to the page with a source point to the adsafeprotected.com domain (you can see this in Alun’s video). The original referrer is passed to this as part of the GET request.
- Ultimately, the response from adsafeprotected.com renders the original URL into the JavaScript context without correctly encoding the original quotes Alun put into the request:
As it turns out, just having the words “safe” and “protected” in the URL doesn’t actually do much! The untrusted data passed in the URL is ultimately executed by the browser and the attacker’s bidding is done. Here’s the main lesson and I’m going to make this rather bold:
When you allow third parties to run script on your site, you’re entirely beholden to them; they can run anything they like in the context of your site.
Now there are some caveats to all this: firstly, ad networks operate by selling ad space to different providers. My agreement is with Developer Media because I want developer-focused content on my site, but if they can’t fill the slots then they sell those off to other providers. That can mean content is coming from different places depending on a whole range of factors including the day and time you load the site, what’s on the page and other demographics specific to you. As a result, I couldn’t actually reproduce this myself. Alun also had to turn of the XSS protection in IE which on the one hand, you shouldn’t do but on the other hand, websites should be resilient to anyway.
The domain adsafeprotected.com is owned by AdSafe Media who has now rebranded as Integral Ad Science. As soon as I could establish what was going on, I emailed both Developer Media and Integral. Nine hours later (which would have been first thing Monday morning for them), Developer Media responded and advised it had been escalated. 25 minutes after that, they advised that “all the ads from that agency are paused until the issue is resolved”. This is the best immediate response Developer Media could have given and I’m enormously happy with their conduct on this. A day and a half later, I still have nothing from Integral.
One of the other things that Alun pointed out is that the adsafeprotected.com domain has previously been reported as serving malware. This was the NeoSploit Exploit Kit which attempts to compromise the host machine via vulnerabilities in the likes of ActiveX and Adobe Reader. Clearly, this is not what I want visitors to my site being exposed to!
I thought about other mechanisms to protect from this style of risk but unfortunately there are no easy answers. A content security policy, for example, could have white-listed trusted sources for scripts and other files but the problem with ad networks is that they’re a labyrinth of redirects and dynamically loaded content from various sources. There’ no simple “Oh everything is loaded from foo.com” style solution.
Ad networks can be the cesspit of the web. Let me just take the first story I can find shared by a friend on Facebook:
Even the first comment is an ad – with 79 likes! I’m not actually sure where the ads stop and the click-bait to their own content (primarily in order to load more ads) begins on this page. This is why I went with developer-centric ads on this blog and it’s also why I’m frankly pretty pissed at a provider within that network being so slack. I get that ads are a commercial necessity for many sites and they sure do make it much easier for me to do what I do as well, but the industry needs a good kick up the arse when even reputable providers like Developer Media can innocuously and unknowingly put their customers at risk this way.