jwtk/jjwt · warning · UnsupportedJwtException

JWE Header ${param} value ${iterations} exceeds ${getId()} m

Error message

JWE Header ${param} value ${iterations} exceeds ${getId()} maximum allowed value ${MAX_ITERATIONS}. The larger value is rejected to help mitigate potential Denial of Service attacks.

What it means

To mitigate DoS attacks, decryption rejects JWE headers whose 'p2c' (PBES2 iteration count) exceeds MAX_ITERATIONS, throwing UnsupportedJwtException. An attacker could otherwise force expensive PBKDF2 computations with a huge iteration count.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/security/Pbes2HsAkwAlgorithm.java:205

        return result;
    }

    @Override
    public SecretKey getDecryptionKey(DecryptionKeyRequest<Password> request) throws SecurityException {

        JweHeader header = Assert.notNull(request.getHeader(), "Request JweHeader cannot be null.");
        final Password key = Assert.notNull(request.getKey(), "Decryption Password cannot be null.");
        ParameterReadable reader = new RequiredParameterReader(header);
        final byte[] inputSalt = reader.get(DefaultJweHeader.P2S);

        Parameter<Integer> param = DefaultJweHeader.P2C;
        final int iterations = reader.get(param);
        if (iterations > MAX_ITERATIONS) {
            String msg = "JWE Header " + param + " value " + iterations + " exceeds " + getId() + " maximum " +
                    "allowed value " + MAX_ITERATIONS + ". The larger value is rejected to help mitigate " +
                    "potential Denial of Service attacks.";
            throw new UnsupportedJwtException(msg);
        }

        final byte[] rfcSalt = Bytes.concat(SALT_PREFIX, inputSalt);
        final char[] password = key.toCharArray(); // password will be safely cleaned/zeroed in deriveKey next:
        final SecretKey derivedKek = deriveKey(request, password, rfcSalt, iterations);

        DecryptionKeyRequest<SecretKey> unwrapReq =
                new DefaultDecryptionKeyRequest<>(request.getPayload(), request.getProvider(),
                        request.getSecureRandom(), header, request.getEncryptionAlgorithm(), derivedKek);

        return wrapAlg.getDecryptionKey(unwrapReq);
    }
}

View on GitHub (pinned to fb71496164)

Solutions

  1. Have the token issuer lower p2c to an allowed value (<= MAX_ITERATIONS, still >= 1000).
  2. Catch UnsupportedJwtException during decryption and reject the token as untrusted.
  3. If the library's cap is too low for your policy, configure/upgrade to a version with the desired cap rather than bypassing validation.

Example fix

// before
try { jwe = Jwts.parser().decryptWith(password).build().parseEncryptedClaims(token); }
catch (UnsupportedJwtException e) { audit("oversized p2c", e); }
// after (issuer side)
headerBuilder.p2c(100000); // within [1000, MAX_ITERATIONS]
Defensive patterns

Strategy: try-catch

Validate before calling

Integer p2c = header.get("p2c", Integer.class);
if (p2c != null && p2c > Pbes2HsAkwAlgorithm.MAX_ITERATIONS) {
    throw new UnsupportedJwtException("p2c exceeds allowed maximum");
}

Try / catch

try {
    Jwe<Claims> jwe = Jwts.parser().decryptWith(password).build().parseEncryptedClaims(token);
} catch (UnsupportedJwtException e) {
    // reject token: p2c too large (possible DoS attempt)
}

Prevention

When it happens

Trigger: Parsing/decrypting a JWE token whose header contains p2c greater than Pbes2HsAkwAlgorithm.MAX_ITERATIONS, or programmatically setting such a value in a DefaultJweHeader used for decryption.

Common situations: Receiving tokens from third parties or attackers with crafted p2c headers; tokens generated by another library without an iteration cap.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/a10dde38a6a97654. Report an issue: GitHub.