HIGH bleichenbacher attackjwt tokens

Bleichenbacher Attack with Jwt Tokens

How Bleichenbacher Attack Manifests in Jwt Tokens

The Bleichenbacher attack is a padding‑oracle attack against RSA PKCS#1 v1.5 encryption. In the JWT world it becomes relevant when a service uses JSON Web Encryption (JWE) with the RSA1_5 algorithm (or relies on a vulnerable RSA PKCS#1 v1.5 signature verification that leaks padding errors). An attacker can capture a legitimate JWE, modify its ciphertext, and send it to the token‑validation endpoint. By observing whether the service returns a distinct error for invalid padding versus a generic validation failure, the attacker can iteratively decrypt the plaintext (often the JWT payload or a symmetric key) without knowing the private key.

Consider a Node.js service that uses the node-jose library to decrypt incoming JWEs:

const jose = require('node-jose');

async function handleToken(req, res) {
  const compactJwe = req.body.jwe; // received from client
  try {
    const result = await jose.JWE.createDecrypt().decrypt(compactJwe);
    const payload = JSON.parse(result.plaintext.toString());
    // process payload
    res.json({ status: 'ok', data: payload });
  } catch (err) {
    // Vulnerable: different messages for padding vs other errors
    if (err.message.includes('padding')) {
      res.status(400).send('Invalid padding');
    } else {
      res.status(400).send('Invalid token');
    }
  }
}

If the service distinguishes padding errors, an attacker can submit crafted ciphertexts and learn whether each trial caused a padding error, gradually revealing the plaintext. The same principle applies to RSA PKCS#1 v1.5 signature verification when the verification routine leaks whether the PKCS#1 padding was correct.

Real‑world analogues include CVE‑2016‑0800 (DROWN) and CVE‑2017‑15361 (ROBOT), which demonstrated that any service exposing PKCS#1 v1.5 padding oracle via error messages is susceptible to Bleichenbacher‑style decryption.

Jwt Tokens-Specific Detection

Detecting a Bleichenbacher‑style weakness in a JWT endpoint does not require source code; it can be done by probing the unauthenticated surface. middleBrick’s active checks include:

  • Identifying whether the endpoint accepts JWEs with the RSA1_5 header.
  • Sending a series of malformed ciphertexts derived from a legitimate token and measuring the response timing or error‑message differences.
  • Checking for verbose error messages that differentiate padding failures from other validation problems.

Example of a middleBrick CLI scan that would surface this issue:

middlebrick scan https://api.example.com/token --format json

The resulting JSON report contains a finding under the "Encryption" category with severity high, describing:

{
  "id": "ENC-RSA1_5-PADDING-ORACLE",
  "title": "RSA PKCS#1 v1.5 padding oracle detected in JWE decryption",
  "description": "The endpoint returns distinct error messages for invalid PKCS#1 v1.5 padding, enabling a Bleichenbacher attack to decrypt JWE payloads.",
  "remediation": "Switch to RSA‑OAEP (e.g., RSA-OAEP-256) and ensure generic error responses for all validation failures.",
  "references": ["https://tools.ietf.org/html/rfc8018#section-7.2.2", "CVE-2017-15361"]
}

middleBrick also checks the JWK/JWKS for keys marked with "alg":"RSA1_5" and flags any usage of that algorithm in runtime JWE processing.

Jwt Tokens-Specific Remediation

The fix is to eliminate the PKCS#1 v1.5 padding oracle by using a scheme that does not leak padding information and by returning uniform error messages. For JWE, replace RSA1_5 with RSA-OAEP-256 (or RSA-OAEP). For JWS signatures, prefer algorithms that do not rely on RSA PKCS#1 v1.5 padding for verification (e.g., ES256, EdDSA) or ensure the verification routine is constant‑time and does not expose padding errors.

Here is the same Node.js endpoint rewritten to use RSA‑OAEP and generic error handling:

const jose = require('node-jose');

async function handleTokenSecure(req, res) {
  const compactJwe = req.body.jwe;
  try {
    // No algorithm restriction – node‑jose will reject unsupported algs
    const result = await jose.JWE.createDecrypt().decrypt(compactJwe);
    const payload = JSON.parse(result.plaintext.toString());
    res.json({ status: 'ok', data: payload });
  } catch (err) {
    // Generic failure – no distinction between padding, key, or format errors
    res.status(400).send('Invalid token');
  }
}

In Python, using the python-jose library:

from jose import jwe, JWTError
import json

def handle_token(compact_jwe):
    try:
        plaintext = jwe.decrypt(compact_jwe, key)  # key is the private RSA key
        payload = json.loads(plaintext.decode('utf-8'))
        return {'status': 'ok', 'data': payload}
    except JWTError:
        # All validation errors map to the same response
        return {'status': 'error', 'message': 'Invalid token'}

# Usage in a web framework (e.g., Flask)
# return jsonify(handle_token(request.json['jwe']))

Additionally, rotate any existing RSA1_5 keys, retire them from the JWKS, and ensure that the server never returns different HTTP status codes or error messages based on the exact validation failure point. After applying these changes, a middleBrick rescan will no longer report the padding‑oracle finding, and the token endpoint will be resistant to Bleichenbacher‑style attacks.

Frequently Asked Questions

Does middleBrick need any credentials or agents to test for Bleichenbacher weaknesses in JWT endpoints?
No. middleBrick performs unauthenticated, black‑box scans by submitting only the target URL. It detects the use of risky JWE algorithms and error‑message differences without requiring API keys, agents, or prior configuration.
If I switch from RSA1_5 to RSA-OAEP, do I also need to change my JWT signing algorithm?
Not necessarily. The Bleichenbacher padding oracle applies to RSA PKCS#1 v1.5 encryption (JWE) and to vulnerable RSA signature verification. Switching the JWE algorithm to RSA-OAEP removes the encryption‑side oracle. For signatures, consider using algorithms that do not rely on RSA PKCS#1 v1.5 padding (e.g., ES256, EdDSA) or verify that your signature library returns generic errors on failure.