# Why Appropriate Content-Type Header Matters In REST API Security: Ft. JSON XSS ## Understanding REST APIs Before diving into the specifics of the Content-Type header, let's quickly recap what REST APIs are all about. REST is an architectural style for designing networked applications. It is based on a set of constraints that encourage the use of standardized HTTP methods like GET, POST, PUT, and DELETE for communication between a client (usually a web or mobile application) and a server. In a RESTful interaction, data is exchanged using various HTTP headers, such as "**Accept**" and "**Content-Type**." These headers provide essential information about the content and structure of the data being sent or received. >The **Content-Type** header is an essential part of HTTP headers used to convey information about the media type or format of the data in the body of an HTTP message, whether it's a request or a response. **This information is vital for both the client and server to interpret and handle the data correctly**. ## Cross-Site Scripting in REST API In general, **Cross-Site Scripting (XSS)** typically does not work in **JSON API** responses when the Content-Type header is set to "**application/json**" because the JSON format inherently does not allow the execution of scripts embedded within the response data. ![](https://hackmd.io/_uploads/r19LR1_bT.png) >When a web browser receives a response with a Content-Type of "application/json," it treats the content as pure data and **does not execute any JavaScript code** within it. Unlike HTML, which can include script tags that execute JavaScript code, JSON is not processed in the same way. ## How I got the Cross-Site Scripting via JSON response In the recent bug hunting activity, I discovered an API endpoint that returns a 404 status code along with the query parameter value reflected in the response body. But the injected javascript payload will not be executed on the browser due to the "**application/json**" content-type value in the response. ![](https://hackmd.io/_uploads/BkOO1Z_Z6.png) ### Verify the "Accept" header. Then I tied the acceptance of the "**text/html**" content type by replacing the "**Accept**" header value with "text/html". The API accept the "text/html" content-type. Observe the content-type header value in the below image. ![](https://hackmd.io/_uploads/rko1QbuZp.png) ### How can we control the "Accept" header. As per the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept#examples), for navigation requests the "Accept" header default values are `text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8`. Therefore, the browser by default, sets the "Accept" header value with "text/html" ![](https://hackmd.io/_uploads/Hk59wZOWa.png) When a legitimate user makes a request to this API, their browser interprets the JSON data as HTML, executes the injected script. ![](https://hackmd.io/_uploads/By-MO-dWa.png) ## Conclusion: * Ensure that your API requests and responses use the appropriate Content-Type header that accurately represents the data being exchanged. Use "application/json" for JSON data * Bug Hunters: Verify the "text/html" content-type acceptance to ensure the security of the API.