The "alg" field of the JOSE header of a JWE token selects the key-wrapping
algorithm, hence the AES key size, while the key itself is the secret
configured by the operator for the "jwt_decrypt_secret" converter. That
secret is stored in an exact-size heap allocation, and neither
decrypt_cek_aeskw() nor aes_process() (used by the AES-GCM key wrap
variant) checked that it was large enough for the selected cipher before
handing its address to OpenSSL.
So a client sending a token that declares A256KW or A256GCMKW while the
configured secret is only 16 bytes long makes OpenSSL read 16 bytes past
the end of that allocation and use them as key material. This is a
remotely triggered heap over-read which may crash the worker, and whose
bytes influence the decryption result.
Let's check the secret length against the cipher's key length in both
paths before initializing the cipher.
Both were introduced in 3.4, by commits
f0e64de75 ("MINOR: ssl: Factorize
AES GCM data processing") and
416b87d5d ("MINOR: jwe: Add new
jwt_decrypt_secret converter"). This must be backported to 3.4.
Reported-by: Claude (ANT-2026-TS9WFQ5T)
Reported-by: Claude (ANT-2026-9T34RNDD)
EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
#endif
+ /* <crypt_alg> comes from the token's JOSE header, so the attacker picks
+ * the key size while the secret is operator-provided: refuse to run if
+ * the secret is shorter than what the cipher will read.
+ */
+ if (b_data(secret) < EVP_CIPHER_key_length(cipher))
+ goto end;
+
iv_size = EVP_CIPHER_iv_length(cipher);
iv = alloc_trash_chunk();
if (!iv)
if (!ctx)
goto err;
+ /* The key size may be dictated by the input (e.g. the "alg" field of a
+ * JWE token), so make sure the configured key is large enough for the
+ * selected cipher, otherwise OpenSSL would read past its end.
+ */
+ if (b_data(key) < key_size / 8)
+ goto err;
+
switch(key_size) {
case 128:
sample_conv_aes_init(decrypt, ctx, (gcm ? EVP_aes_128_gcm() : EVP_aes_128_cbc()),