JSON security vulnerabilities can expose applications to injection attacks, data leakage, and remote code execution. Unlike SQL injection, which targets databases, JSON-based attacks target parsers, validators, and downstream consumers. Understanding these risks is essential for any application processing untrusted JSON. Common vulnerabilities include prototype pollution, eval injection, and parser differential attacks. Modern parsers are generally secure, but misconfigurations and custom handling can introduce vulnerabilities.

Prototype Pollution Prevention

Prototype pollution occurs when attacker-controlled JSON modifies Object.prototype, affecting all objects. This vulnerability affects applications that merge user JSON into objects without deep cloning safely. Prevent by freezing Object.prototype, using Object.create(null) for merged objects, blocking __proto__ and constructor keys, or using libraries like deep-freeze-es6. Node.js provides --disable-prototype-polluion flag for stricter parsing. Always validate and sanitize JSON before merging into objects.

JSON Injection Attacks

JSON injection occurs when user input is embedded in JSON without proper escaping, potentially breaking out of the JSON structure. This can lead to Cross-Site Scripting (XSS) when JSON is parsed and rendered by browsers. Prevent by never concatenating user input directly into JSON strings; always use JSON.stringify() with a replacer function. When displaying JSON in HTML, escape HTML entities. Validate content-type headers to ensure responses are actually JSON. These practices prevent the most common injection vectors.

Eval and Function Constructor Risks

Using eval() or the Function constructor to parse JSON is extremely dangerous and should never be done. These functions execute arbitrary JavaScript, enabling remote code execution attacks. Even if you trust your JSON source, never use eval() for parsing—JSON.parse() is faster and safer. Be wary of libraries that use eval internally; audit your dependencies. The same warning applies to Function(), setTimeout(string), and similar patterns that execute strings as code.

// DANGEROUS - eval executes arbitrary code
const user = eval('(' + untrustedJSON + ')');

// Safe - JSON.parse only parses JSON data
try {
  const user = JSON.parse(untrustedJSON);
  console.log(user.name);
} catch (err) {
  console.error("Invalid JSON input:", err.message);
}
// Node.js input validation for JSON payloads
const express = require('express');
const app = express();

app.use(express.json({ limit: '1mb' }));

app.post('/api/users', (req, res) => {
  const { name, email } = req.body;
  if (typeof name !== 'string' || name.length === 0) {
    return res.status(400).json({ error: 'Invalid name' });
  }
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
    return res.status(400).json({ error: 'Invalid email' });
  }
  res.status(201).json({ id: 123, name, email });
});

app.listen(3000);

Parser Differential Attacks

Parser differential attacks exploit differences between how different JSON parsers interpret ambiguous input. Valid JSON in one parser might be invalid or malicious in another. These attacks can bypass security checks that rely on specific parser behavior. Mitigate by using strict parsers, validating against schemas, and ensuring consistent parsing across your stack. When accepting JSON from external sources, parse conservatively and reject ambiguous input. Tools like fuzzer harnesses can discover parser differences in your dependencies.

Denial of Service via Large Payloads

Maliciously large JSON payloads can exhaust server memory and crash parsers. Implement payload size limits at the API gateway, application, and parser level. Set reasonable timeouts for parsing operations. For file uploads, verify Content-Length before reading. Consider streaming parsers for large datasets to process incrementally. Monitor memory usage and reject payloads that exceed reasonable bounds. These protections prevent resource exhaustion attacks.

Type Confusion Vulnerabilities

Type confusion occurs when JSON data is interpreted differently than expected, leading to bypasses of type-based security checks. For example, a boolean true might be accepted where a string is expected. Validate types explicitly using schema validation, not just existence checks. Use strict type checking throughout your application. Libraries like Zod and Yup provide comprehensive type validation. Document expected types clearly and reject unexpected types aggressively.

Securing JSON APIs

JSON APIs require authentication, authorization, and input validation. Always verify Content-Type is application/json to prevent content sniffing attacks. Implement rate limiting to prevent brute force and abuse. Log all requests with sufficient detail for security auditing. Use HTTPS exclusively to prevent man-in-the-middle attacks. Consider request signing for sensitive operations. These measures protect your API from common attack vectors.

Dependency Security

JSON parsing libraries can contain vulnerabilities. Regularly audit dependencies with npm audit or Snyk. Update parsers to latest versions to patch known vulnerabilities. Prefer well-maintained libraries with good security track records. Consider using multiple parsing layers—parsing with your library, then validating with a schema validator. This defense in depth catches issues that might slip past one parser. Subscribe to security advisories for your dependencies.

Security Testing for JSON Applications

Comprehensive security testing catches JSON vulnerabilities before attackers do. Include JSON injection and prototype pollution in your threat model. Use automated scanners like OWASP ZAP for common vulnerabilities. Conduct code review focused on data flow from JSON input to sensitive operations. Penetration test your APIs with tools that specialize in JSON-based attacks. Document security requirements and verify them in CI/CD pipelines.