Poodle Attack in Adonisjs with Jwt Tokens
Poodle Attack in Adonisjs with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A Poodle (Padding Oracle On Downgraded Legacy Encryption) attack targets cryptographic implementations that allow an attacker to iteratively decrypt ciphertext by exploiting a padding oracle. While Poodle is classically associated with TLS and block cipher modes, analogous oracle conditions can arise in application code that performs encryption or decryption of sensitive data such as JSON Web Tokens (JWTs). In AdonisJS, a JWT token implementation that uses AES-CBC (or a custom block cipher mode with padding) and exposes behavior that reveals whether padding is valid can create an effective padding oracle within the application layer.
Consider an AdonisJS service that decrypts a JWT token and then validates its signature and claims. If the decryption routine is implemented in a way that returns distinct errors for invalid padding versus invalid signature or malformed tokens, an attacker can perform a chosen-ciphertext attack. For example, the attacker sends modified ciphertexts and observes differences in HTTP status codes, response times, or error messages. A typical vulnerable pattern is a decrypt function that throws a low-level padding error before checking the token signature, effectively leaking information about padding correctness to the remote attacker.
In AdonisJS, this often occurs when developers use generic cryptographic libraries without strict error handling and constant-time comparison. A JWT token encrypted with AES-CBC may be passed to a decryption routine; if the routine first decrypts and then validates structure, the padding removal step can throw an exception when padding is incorrect. Because the application propagates these errors differently than signature validation failures, the attacker can gradually decrypt the token or recover plaintext by iteratively querying the endpoint with manipulated tokens.
Another contributing factor is the use of predictable or missing initialization vectors (IVs). If the IV is static or derived in a predictable way, the attacker may more easily mount adaptive chosen-ciphertext attacks that align with Poodle-like conditions. Even when using JWTs, which are commonly represented as JSON serialized data, encrypting the serialized payload with a mode that does not provide integrity or authentication at the cryptographic layer (e.g., AES-CBC without HMAC or an AEAD mode) can expose padding oracle behavior.
To map this to real-world attack patterns, consider an endpoint like POST /auth/token that accepts an encrypted JWT. If the server returns 400 for malformed tokens but a different internal error when padding is invalid, the distinction becomes an oracle. An attacker can intercept and modify ciphertext blocks, using the server’s responses to infer padding correctness and eventually decrypt the token without needing the secret key. This compromises the confidentiality and integrity of the JWT claims, potentially leading to privilege escalation or session hijacking.
middleBrick detects such risks as part of its 12 security checks, including Input Validation and Unsafe Consumption, by analyzing how endpoints handle malformed or malicious payloads and whether error handling leaks cryptographic distinctions. The scanner evaluates whether runtime behavior reveals padding oracle conditions and highlights findings mapped to frameworks like OWASP API Top 10 and common weaknesses such as CWE-306 or CWE-725.
Jwt Tokens-Specific Remediation in Adonisjs — concrete code fixes
Remediation focuses on ensuring that decryption and validation are performed in a way that does not leak padding information and that errors are handled uniformly. The primary defense is to use authenticated encryption with associated data (AEAD) modes such as AES-GCM, which provide both confidentiality and integrity in a single operation and do not require manual padding management. If AES-CBC is required, you must implement strict error handling that does not distinguish between padding errors and other failures, and you must use constant-time comparison for any integrity checks.
Below are concrete AdonisJS code examples that demonstrate a secure approach for handling JWTs. The first example uses an AEAD mode via a library that supports it, avoiding padding issues entirely.
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
export class JwtCrypto {
private algorithm = 'aes-256-gcm';
private key: Buffer;
constructor(key: string) {
this.key = Buffer.from(key, 'hex');
}
encrypt(payload: object): { ciphertext: string; iv: string; authTag: string } {
const iv = randomBytes(12);
const cipher = createCipheriv(this.algorithm, this.key, iv);
const plaintext = Buffer.from(JSON.stringify(payload));
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
const authTag = cipher.getAuthTag();
return {
ciphertext: ciphertext.toString('base64'),
iv: iv.toString('base64'),
authTag: authTag.toString('base64'),
};
}
decrypt(ciphertextBase64: string, ivBase64: string, authTagBase64: string): object {
const ciphertext = Buffer.from(ciphertextBase64, 'base64');
const iv = Buffer.from(ivBase64, 'base64');
const authTag = Buffer.from(authTagBase64, 'base64');
const decipher = createDecipheriv(this.algorithm, this.key, iv);
decipher.setAuthTag(authTag);
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
return JSON.parse(plaintext.toString());
}
}
This approach uses AES-GCM with a random 96-bit IV per encryption and produces an authentication tag. Because GCM is an AEAD mode, there is no padding, and decryption either succeeds and verifies the authentication tag or fails with a generic error, preventing padding oracles.
If you must use AES-CBC, ensure errors are opaque and use constant-time comparison for any MAC or signature validation. Here is an example that avoids leaking padding information:
import crypto from 'crypto';
export class JwtCryptoCbc {
private algorithm = 'aes-256-cbc';
private key: Buffer;
constructor(key: string) {
this.key = Buffer.from(key, 'hex');
}
encrypt(payload: object): { ciphertext: string; iv: string } {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
const plaintext = Buffer.from(JSON.stringify(payload));
let ciphertext = cipher.update(plaintext);
ciphertext = Buffer.concat([ciphertext, cipher.final()]);
return { ciphertext: ciphertext.toString('base64'), iv: iv.toString('base64') };
}
decrypt(ciphertextBase64: string, ivBase64: string): object {
const ciphertext = Buffer.from(ciphertextBase64, 'base64');
const iv = Buffer.from(ivBase64, 'base64');
let plaintext: Buffer;
try {
const decipher = crypto.createDecipheriv(this.algorithm, this.key, iv);
plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
} catch (err) {
// Always throw a generic error to avoid padding oracle
throw new Error('decryption failed');
}
return JSON.parse(plaintext.toString());
}
}
In this CBC example, the catch block throws a generic error, ensuring that padding errors do not propagate as distinct messages. Additionally, you should ensure that the JWT signature validation occurs after decryption and that any integrity checks use constant-time comparison to avoid timing leaks.
Other remediation practices include using a strong, randomly generated key stored securely, rotating keys with a key management strategy, and ensuring that IVs are unique and unpredictable per encryption. Avoid static or predictable IVs, and never reuse an IV with the same key in AES-CBC. middleBrick’s checks for Data Exposure and Encryption help identify weak cryptographic practices and missing protections around JWT handling.
Finally, prefer standardized compact serialization formats and libraries that implement best practices, such as using the jsonwebtoken library with proper configuration or leveraging Auth0/Okta managed tokens where feasible. Combine these technical controls with monitoring and anomaly detection to identify suspicious decryption patterns that may indicate active oracle attacks.