Double Free with Jwt Tokens
How Double Free Manifests in JWT Tokens
While "double free" is classically a memory corruption vulnerability in C/C++, it can manifest in JWT token handling through improper memory management in native JWT parsing libraries or in garbage-collected languages when interacting with native bindings. The attack pattern involves an attacker crafting a malicious JWT that, during parsing or validation, triggers a code path where memory is freed twice. This can lead to crashes, information leakage, or in worst-case scenarios, arbitrary code execution if the attacker can control the freed memory layout.
In JWT-specific contexts, this often occurs in libraries that use low-level parsing for performance. For example, a JWT library might allocate memory for the token's header and payload, then attempt to free that memory in both a success path and an error path (e.g., during signature verification failure or malformed token handling). If an attacker sends a token with an invalid signature but a valid structure, the parser might allocate memory, fail verification, attempt to free, then later attempt to free again during cleanup or in a subsequent request that reuses a corrupted token cache.
A concrete instance is CVE-2022-23529 in the jsonwebtoken library for Node.js (versions before 8.5.1). The vulnerability existed in the jwt.verify() function when handling tokens with "compact serialization" and a malformed "kid" (key ID) parameter. The library's native binding (via node-jose) could be tricked into a state where memory was freed during error handling, then freed again when the JWT object was garbage collected, leading to a double-free condition.
Attackers typically probe for this by sending tokens with:
- Excessively long
kidvalues that cause buffer overflows in native code - Tokens with mismatched encoding (e.g., mixing base64url and base64)
- Tokens that trigger specific error conditions in the library's parsing state machine
Because JWT tokens are often used for authentication and session management, a double-free in a JWT library can compromise the entire application's integrity, especially if the library runs in a privileged process or with access to sensitive keys.
JWT Tokens-Specific Detection
Detecting double-free vulnerabilities in JWT handling requires both static analysis of library versions and dynamic testing of token parsing endpoints. Since this is a memory corruption issue, it often doesn't produce clear HTTP error responses; instead, it may cause crashes, memory leaks, or abnormal process behavior. Black-box scanning like middleBrick's approach focuses on the observable effects of such crashes or the presence of vulnerable library versions in responses.
middleBrick's Input Validation and Authentication checks test JWT endpoints by submitting a battery of malformed tokens, including:
- Tokens with oversized
kidheaders (e.g., 10KB strings) - Tokens with invalid base64url padding or characters
- Tokens with duplicate claims or circular references in JSON
- Tokens that mix encryption and signing (e.g., JWE with JWS confusion)
The scanner monitors for anomalous responses: HTTP 500 errors with stack traces indicating memory allocation functions (like malloc, free in C-based libraries), connection resets, or unusually long response times that suggest process crashes and restarts. It also fingerprints JWT library versions by analyzing error message patterns and header structures, then correlates these with known vulnerability databases (like CVE) that list double-free issues.
For example, scanning an endpoint that accepts JWTs via Authorization: Bearer <token> might reveal:
POST /auth/token/validate HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im15a2V5Zm9yZGV2aWxz... (10KB kid)
HTTP/1.1 500 Internal Server Error
Server: nginx/1.18.0
X-Powered-By: Express
{"error":"Memory allocation failed"}This pattern, especially with a known vulnerable library version (e.g., [email protected]), raises a high-severity finding. middleBrick's report would categorize this under Input Validation or Authentication, with a severity based on exploitability and potential impact.
Additionally, middleBrick's OpenAPI/Swagger analysis cross-references the API specification's security schemes (e.g., BearerAuth) with runtime behavior. If the spec indicates JWT usage but the endpoint accepts tokens without proper validation or shows crash patterns, it flags potential implementation flaws that could include double-free conditions.
JWT Tokens-Specific Remediation
Remediation for double-free vulnerabilities in JWT handling centers on updating libraries, validating input lengths, and ensuring proper error handling in token parsing code. Since the flaw is often in a third-party library, the first step is to upgrade to a patched version. Developers must also defensively code around JWT parsing to avoid triggering the vulnerable paths.
1. Update JWT Libraries Immediately
Check your dependency tree for vulnerable versions. For Node.js with jsonwebtoken:
# Check for vulnerable versions
npm ls jsonwebtoken
# Upgrade to patched version (>=8.5.1 for CVE-2022-23529)
npm install jsonwebtoken@latestFor Python with PyJWT, ensure you're on a version that has addressed any native binding issues (though PyJWT is pure Python, it may use cryptography library which has had memory bugs).
2. Validate JWT Structure Before Parsing
Implement early checks on token size and header fields to prevent oversized or malformed tokens from reaching vulnerable parsing code:
// Node.js example with jsonwebtoken
const jwt = require('jsonwebtoken');
function safeVerify(token, secret) {
// Basic sanity checks before calling jwt.verify()
if (typeof token !== 'string' || token.length > 8192) {
throw new Error('Invalid token size');
}
// Split token to inspect header without full parse
const parts = token.split('.');
if (parts.length !== 3) {
throw new Error('Invalid token format');
}
// Decode header only (base64url decode)
const header = JSON.parse(Buffer.from(parts[0], 'base64url').toString());
if (header.kid && header.kid.length > 128) {
throw new Error('kid too long');
}
// Now proceed with verification
return jwt.verify(token, secret, { algorithms: ['HS256'] });
}3. Use Try-Catch and Isolate Parsing
Wrap JWT operations in try-catch blocks and avoid reusing token objects across requests. In languages with manual memory management (like Go with CGO), ensure that any native JWT parsing results are freed exactly once in all error paths.
4. Implement Token Size Limits at the Proxy Level
Configure your API gateway or load balancer to reject JWTs exceeding a reasonable size (e.g., 4KB). This prevents maliciously large tokens from reaching your application.
5. Monitor and Alert on Parsing Errors
Log and alert on spikes in JWT validation failures, especially those indicating malformed tokens. This can be an early indicator of exploitation attempts targeting parsing vulnerabilities.
After applying fixes, rescan with middleBrick to confirm that the Input Validation and Authentication checks no longer flag the endpoint for anomalous token handling. The remediation guidance in middleBrick's report will point to the specific check (e.g., "JWT token parsing error patterns") so you can verify the fix.