Security
JSON Security: Preventing Vulnerabilities in Modern Applications
Published: 2026-05-09 · 3 min read | By Li Xiaoyao
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.
Common JSON Security Vulnerabilities: A Threat Model Analysis
JSON's apparent simplicity masks several significant security vulnerabilities that developers must understand and mitigate. JSON Injection: When user-controlled strings are concatenated directly into JSON documents without proper escaping, attackers can inject arbitrary structure. For example, if a user's name is constructed as {"name": "USER_INPUT"}, an attacker could input "}, {"role": "admin" and break out of the intended structure. Always use proper JSON serialization libraries—never construct JSON through string concatenation.
Prototype Pollution: JavaScript's prototypal inheritance model creates a unique vulnerability in JSON processing. When merging user-supplied JSON objects with configuration objects, properties like "__proto__" or "constructor.prototype" can modify Object.prototype, affecting all objects in the application. Mitigation: use safe merge utilities that explicitly ignore "__proto__", "constructor", and "prototype" properties, or use Object.create(null) to create dictionary objects without prototype chains.
XXE in JSON: While JSON itself doesn't support document type definitions (DTD), many JSON parsing libraries that also handle XML or YAML may process embedded XML content. If your application converts JSON to XML or handles JSON within XML contexts, disable external entity processing in your XML parser. Modern parsers disable XXE by default, but older library versions may still be vulnerable.
Key Insight: Prototype pollution through `__proto__` and `constructor` keys is unique to JavaScript's inheritance model. Use `Object.create(null)` for merged objects and freeze `Object.prototype` to prevent attacker-controlled JSON from affecting all objects in your application.
JWT Security: Common Pitfalls and Prevention
JSON Web Tokens are widely used for authentication, but incorrect implementation frequently leads to critical vulnerabilities. Algorithm confusion attacks: If your JWT validation library accepts the "alg" header without verifying it against a whitelist, attackers can switch from RS256 (asymmetric) to HS256 (symmetric) and sign tokens using the public key (which they can obtain from well-known JWKS endpoints) as the HMAC secret. Always whitelist accepted algorithms and never trust the "alg" header value without server-side confirmation.
Missing signature verification: The most common and dangerous JWT mistake. Some developers set the algorithm to "none" for testing and forget to remove it in production, or configure libraries to skip signature verification entirely. Always explicitly require signature verification in production. Use libraries that default to secure configurations rather than requiring explicit security settings.
Token storage: Storing JWTs in localStorage exposes them to XSS attacks. Any JavaScript running on the page can read localStorage. Use httpOnly, Secure, SameSite cookies for JWT storage. This prevents JavaScript access to the token and mitigates XSS-based token theft. For SPAs, consider the BFF (Backend For Frontend) pattern where tokens are managed server-side with a session cookie.
Key Insight: Algorithm confusion attacks exploit the most common JWT misconfiguration—trusting the `alg` header without server-side whitelisting. Always explicitly specify accepted algorithms; never let the client choose.
Sensitive data in token payload: Remember that JWT payloads are Base64-encoded, not encrypted. Anyone with the token can decode and read the payload. Never include sensitive information (passwords, credit card numbers, personal data) in JWT claims. Use opaque references to server-side sessions when sensitive data is required.
Preventing JSON Bombs and Denial of Service Attacks
JSON bombs are small JSON documents that expand to consume enormous resources when parsed. The classic example: a deeply nested array like [[[[...]]]] with 10,000 levels of nesting can cause stack overflow in recursive parsers. A circular reference bomb using "$ref" can cause infinite loops in schema validators. Mitigation: set strict limits on nesting depth (maximum 20 levels), document size (maximum 10MB), and array/object element counts (maximum 10,000), and validate these limits before processing.
Billion laughs attack: While primarily an XML vulnerability, JSON processors that support entity expansion or reference resolution can be vulnerable to similar attacks. A small payload that defines nested references can expand to consume gigabytes of memory during resolution. Set limits on reference depth and total expanded size.
Zip bombs via compressed JSON: If your API accepts gzipped JSON uploads, a 1KB gzipped file could decompress to gigabytes of repeated data. Always check the decompressed size before processing compressed uploads, and set hard limits on accepted payload sizes regardless of compression ratio.
Key Insight: A 1KB gzipped JSON bomb can decompress to gigabytes. Validate decompressed size before processing compressed uploads, set hard nesting depth limits (≤20 levels), and enforce maximum array/object element counts at the parser level.
Regex DoS (ReDoS): JSON Schema validators that use user-supplied "pattern" keywords can be vulnerable to catastrophic backtracking if the regex engine encounters pathological patterns. Sanitize or reject regex patterns that could cause exponential backtracking, or use regex engines designed to prevent ReDoS (like RE2 or Rust's regex crate).
Secure JSON Processing Pipeline Architecture
Building a secure JSON processing pipeline requires defense in depth across multiple layers. Input layer: Validate Content-Type headers (only accept application/json), enforce size limits at the reverse proxy/load balancer level, implement rate limiting per IP/user, and scan for malicious payloads using Web Application Firewall (WAF) rules specific to JSON injection patterns.
Parsing layer: Use well-maintained JSON parsing libraries with active security support. Set strict parsing options: disable duplicate key tolerance, set maximum depth limits, enforce UTF-8 encoding, and reject JSON with BOM characters or non-standard whitespace. Parse into strongly typed data structures rather than generic dictionaries to prevent type confusion attacks.
Validation layer: Validate parsed data against JSON Schema definitions before any business logic executes. This catches structural errors, type mismatches, and business rule violations early. Failed validation should return detailed error messages in development but generic "Invalid request" responses in production to prevent information leakage.
Key Insight: Every layer in the processing pipeline validates independently—input layer checks Content-Type and size, parsing layer enforces depth limits, validation layer applies schema rules, and business logic layer verifies authorization. No single layer's check is sufficient.
Business logic layer: Apply application-specific security rules. Validate authorization (does this user have permission to perform this action on this resource?), enforce business constraints (can this order be modified in its current state?), and log security-relevant events for audit trails. Never trust that validation at earlier layers is sufficient—defense in depth means every layer validates independently.