Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Security Risks of eval()-Based JSON Parsing

Parsing JSON data is a fundamental task in web development, especially when interacting with APIs. JSON (JavaScript Object Notation) is widely used due to its simplicity and direct mapping to JavaScript objects. However, how you parse JSON matters significantly, particularly from a security standpoint. An outdated and dangerous method, unfortunately still sometimes encountered in older codebases, is using the JavaScript eval() function to parse JSON strings.

This article explores the severe security implications of using eval() for JSON parsing and strongly advocates for the modern and safe alternative, JSON.parse().

What Does eval() Do (and Why Is It Dangerous)?

The eval() function in JavaScript is powerful and inherently risky. It takes a string as an argument and executes it as if it were JavaScript code.

const codeString = "console.log('Hello, World!');";
eval(codeString); // Executes the string as JS code

While this might seem convenient, the danger lies in the fact that eval() will execute *any* valid JavaScript code contained within the string, not just code that represents a data structure.

The Core Risk: Arbitrary Code Execution

When you use eval() to parse a JSON string received from an external source (like an API, user input, etc.), you are essentially trusting that the source will *only* send valid JSON and nothing else. If an attacker can control or inject data into the JSON string your application receives, they can insert malicious JavaScript code that eval() will then execute within the context of your page or server environment.

This allows attackers to perform actions like:

  • Stealing sensitive user data (cookies, local storage, input values).
  • Performing actions on behalf of the user (e.g., making requests to other parts of your application or third-party sites).
  • Defacing your application's UI.
  • Redirecting users to malicious sites.
  • In server-side Node.js environments, potentially accessing local files or executing system commands (depending on surrounding code and privileges).

Malicious Payload Examples

Consider a scenario where your application expects JSON like {"name": "Alice", "age": 30}and parses it using eval('(' + jsonData + ')') (the parentheses are sometimes used to force the string to be interpreted as an expression). An attacker might send a payload like this:

Example 1: Data Exfiltration

const maliciousJson = `
{
  "name": "Attacker",
  "age": 99,
  "__proto__": {
    "toString": () => { // Inject code into a standard object method
      alert('Data stolen: ' + document.cookie); // Or send it to an attacker's server
      return 'Injected';
    }
  }
}
`;
// Assuming eval() is used:
// eval('(' + maliciousJson + ')');
// If the resulting object is later stringified or used in contexts that call toString,
// the malicious code runs.

This example exploits prototype manipulation, which can be executed by eval(). When the resulting object or its properties are later processed (e.g., converting to string), the injected code runs.

Example 2: Direct Code Execution

const anotherMaliciousJson = `
{
  "data": "some value"
}, alert('You have been hacked!'); // Malicious code outside the object
`;
// Assuming eval() is used:
// eval('(' + anotherMaliciousJson + ')');
// The alert('You have been hacked!') part executes.

This example shows how easily code can be appended or injected into a string intended for eval(). Anything after a valid JSON structure within the string passed to eval() can be executed as subsequent JavaScript statements.

JSON Hijacking and eval()

While less common now due to browser protections, in older web environments,eval()-based JSON parsing was linked to a vulnerability called JSON Hijacking.

If sensitive data was returned as a simple JSON array (e.g., [{...}, {...}]), this response was also a valid JavaScript array literal. In some scenarios (especially pre-ES5 browsers or specific execution contexts like overriding Array constructors), the malicious page could potentially read the values of this array. Similarly, if it was a simple object literal ({...}), it could potentially be assigned to a variable if the response was wrapped in parentheses.

A malicious page on another domain could include a script tag pointing to the vulnerable endpoint. Because JavaScript allows executing code from different origins (subject to SOP for reading responses), if the endpoint returned JSON data formatted as an array or object literal and the browser didn't have robust cross-origin read blocking, the malicious script could potentially capture and access the data through eval() or other means that interpreted the response directly as JavaScript code.

Modern browsers and the widespread use of JSON.parse() mitigate this specific attack vector significantly, but it highlights the fundamental danger of treating data from an untrusted source as executable code.

The Safe Alternative: JSON.parse()

The correct and secure way to parse JSON in JavaScript (both browser and Node.js) is by using the built-in JSON.parse() method.

const safeJsonString = '{"name": "Alice", "age": 30}';
try {
  const parsedData = JSON.parse(safeJsonString);
  console.log(parsedData.name); // Output: Alice
} catch (error) {
  console.error("Failed to parse JSON:", error); // Handles invalid JSON
}

JSON.parse() is designed *specifically* for parsing JSON. It is a dedicated parser that understands the JSON specification. It does *not* execute the content of the string as JavaScript code. If the input string is not valid JSON, JSON.parse() will throw a SyntaxError, preventing any malicious code from being executed.

JSON.parse() vs. eval() for JSON

  • Security: JSON.parse() is safe because it only parses data; it doesn't execute code. eval() is unsafe because it executes *any* code, including malicious injections.
  • Performance: JSON.parse() is significantly faster and more efficient than eval() for parsing JSON, as it's optimized for this specific task.
  • Strictness: JSON.parse() strictly enforces the JSON format. eval() is more lenient and might accept things that are valid JavaScript literals but not valid JSON (e.g., using single quotes for strings, trailing commas, comments). This strictness helps catch malformed data.
  • Purpose: JSON.parse()'s sole purpose is parsing JSON. eval()'s purpose is general code execution, which is overly broad and dangerous for data parsing.

Conclusion: Always Use JSON.parse()

The use of eval() for parsing JSON is a severe security vulnerability and should be avoided under all circumstances, especially when dealing with data from external or untrusted sources. Modern JavaScript environments provide the dedicated, secure, and performant method JSON.parse().

If you encounter old code that uses eval() for JSON parsing, it should be refactored immediately to use JSON.parse(). This simple change is a critical step in protecting your application and users from arbitrary code execution attacks.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool