{"id":"PYSEC-2026-3552","summary":"cryptography: PKCS#7 EnvelopedData decryption exposes a Bleichenbacher oracle through distinguishable errors and timing","details":"### Summary\n\n`pkcs7_decrypt_der`, `pkcs7_decrypt_pem`, and `pkcs7_decrypt_smime` reported the\noutcome of decrypting a `RecipientInfo`'s `encryptedKey` in several\ndistinguishable ways, one of which disclosed the exact length recovered from the\nRSA operation. The same distinction was also observable by timing. An\napplication that decrypts attacker-supplied `EnvelopedData` and reflects the\noutcome gives the attacker a Bleichenbacher oracle against the\ncontent-encryption key.\n\nIntroduced in 44.0.0. Fixed in 50.0.0.\n\n### Details\n\nDecryption ran as: RSA PKCS#1 v1.5 decrypt of `encryptedKey` → build an AES\ncipher from the result → AES-CBC decrypt and PKCS#7 unpad. Each stage failed\ndifferently, with no RFC 3218 mitigation:\n\n1. invalid RSA padding → `Decryption failed`\n2. valid padding, bad key length → `Invalid key size (N) for AES.`, disclosing `N`\n3. correct length, wrong key → `Invalid padding bytes.`\n4. the real key → plaintext\n\nCase 1 is reachable only where the linked library lacks implicit rejection:\nOpenSSL 3.0 and 3.1, LibreSSL, and BoringSSL. On OpenSSL 3.2+, used in our wheels,\ninvalid padding instead returns a synthetic plaintext of\npseudorandom length, so the error channel does not distinguish conforming\nciphertexts.\n\nExploitation requires a service that auto-decrypts untrusted `EnvelopedData`\nmatching the victim certificate and answers adaptively at high volume, such as\nan S/MIME gateway or mail filter.\n\n### Fix\n\nPer RFC 3218, the content-encryption algorithm is now resolved before the\nprivate key is used, so the expected key length is known in advance. If the RSA\ndecryption fails or recovers a key of the wrong length, a random key of the\nexpected length is substituted and decryption continues down an identical path.\nAll failures now report identically and perform the same work.\n\n### Not addressed by this fix\n\n`EnvelopedData` does not authenticate its content. Tampering with\n`encryptedContent` alone yields a CBC padding oracle that recovers plaintext at\nroughly 256 queries per byte, without recovering any key, on every backend. This\nis a property of PKCS#7 rather than of this implementation, cannot be fixed in\nthe library, and is now documented.\n\n### Credit\n\nReported by @X1AOxiang.","aliases":["CVE-2026-69247","GHSA-g6cj-pr64-35w5"],"modified":"2026-08-04T14:30:15.036332054Z","published":"2026-08-04T11:34:47.697724Z","references":[{"type":"WEB","url":"https://github.com/pyca/cryptography/security/advisories/GHSA-g6cj-pr64-35w5"},{"type":"WEB","url":"https://github.com/pyca/cryptography/pull/15369"},{"type":"WEB","url":"https://github.com/pyca/cryptography/commit/53fccd93413a8d7f07d6d8999681f27b75cffa3f"},{"type":"PACKAGE","url":"https://github.com/pyca/cryptography"},{"type":"PACKAGE","url":"https://pypi.org/project/cryptography"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-g6cj-pr64-35w5"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-69247"}],"affected":[{"package":{"name":"cryptography","ecosystem":"PyPI","purl":"pkg:pypi/cryptography"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"44.0.0"},{"fixed":"50.0.0"}]}],"versions":["44.0.0","44.0.1","44.0.2","44.0.3","45.0.0","45.0.1","45.0.2","45.0.3","45.0.4","45.0.5","45.0.6","45.0.7","46.0.0","46.0.1","46.0.2","46.0.3","46.0.4","46.0.5","46.0.6","46.0.7","47.0.0","48.0.0","48.0.1","49.0.0"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/cryptography/PYSEC-2026-3552.yaml"}}],"schema_version":"1.8.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N"}]}