I have a web service that takes POST data (JSON) and returns part of the request object in the JSON response.

This is open to XSS if the response is rendered as HTML by the browser since someone could add arbitrary HTML to the request object.

What is the standard way to mitigate this? Current options I can think of are:

  • Only allow requests with X-Requested-With: XMLHttpRequest header to stop attacks that rely on non-ajax requests to my service
  • Send the response with content type application/json and hope the browser refuses to render this as HTML
  • Encode unsafe characters in the response (how do I do this? using \uxxxx?)

I have been unable to find a concrete reference on this.

3 Answers 3


Encode unsafe characters in the response (how do I do this? using \uxxxx?)

Yes. < to \u003C in particular.

There may be an option in your JSON encoder to do this already (eg in PHP, JSON_HEX_TAG); otherwise, it's a simple job to do a string replace after the encoding. (This is safe as there is no place a < may legally be used in JSON other than in a string literal.) At this point you can also include the leading chaff to prevent cross-origin script inclusion.

I would send as application/json as a matter of correctness, but I wouldn't trust every older browser to necessarily honour it. Relying on the X-Requested-With header is generally problematic as it doesn't play well with caching, though that may not be a concern for you.

  • 1
    As noted by Erlend, if you're going to use Content-Type: application/json as a security measure, then it makes sense to serve X-Content-Type-Options: nosniff as well, since this will protect IE 8 and 9 users against the MIME sniffing exploit I describe in the second half of this answer. (Of course, if you're already HTML-encoding all < characters then this is redundant, as is the application/json header itself from a security perspective.)
    – Mark Amery
    Commented Jan 19, 2014 at 12:05

The following points should be kept in mind

  • The potential XSS vulnerability can be avoided by using the correct Content-Type. All JSON responses should use the application/json type.

  • The nosniff header is used to disable content-sniffing on old versions of Internet Explorer.

  • Always have the outside primitive be an object for JSON strings:


[{"object": "inside an array"}]

Not exploitable:

{"object": "not inside an array"}

Also not exploitable:

{"result": [{"object": "inside an array"}]}

Set the Content-Type to application/json, and set X-Content-Type-Options: nosniff (the last header instructs the browser to use the given content-type - no extra guessing). You could even consider adding a Content-Disposition: attachment header. This will be ignored by XHR requests, but cause the download dialog to pop if an attacker tries to trick a user into opening it directly in the browser.

You could also have a look at: http://erlend.oftedal.no/blog/?blogid=127 and http://erlend.oftedal.no/blog/?blogid=134

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .