CVE-2026-69247 Overview
CVE-2026-69247 affects the Python cryptography package from version 44.0.0 up to (but not including) 50.0.0. The pkcs7_decrypt_der, pkcs7_decrypt_pem, and pkcs7_decrypt_smime functions leak information about RecipientInfoencryptedKey decryption failures through distinguishable error paths and timing differences. An attacker who can submit adaptively chosen EnvelopedData to a service that reflects the outcome recovers a Bleichenbacher oracle against the RSA content-encryption key. The vulnerability maps to [CWE-208: Observable Timing Discrepancy].
Critical Impact
Attackers with access to services that auto-decrypt attacker-controlled S/MIME or PKCS#7 messages can recover plaintext content-encryption keys via a Bleichenbacher-style padding oracle attack.
Affected Products
- Python cryptography package versions 44.0.0 through 49.x
- Applications linking OpenSSL 3.0, OpenSSL 3.1, LibreSSL, or BoringSSL (libraries lacking RSA implicit rejection)
- S/MIME gateways, mail filters, and services performing automated PKCS#7 EnvelopedData decryption
Discovery Timeline
- 2026-08-03 - CVE-2026-69247 published to NVD
- 2026-08-04 - Last updated in NVD database
Technical Details for CVE-2026-69247
Vulnerability Analysis
The cryptography package's PKCS#7 decryption path performs four sequential operations: RSA PKCS#1 v1.5 decrypt of the encryptedKey, AES cipher construction from the recovered key, AES-CBC decryption of the content, and PKCS#7 unpadding. Each failure mode returns a distinct error, and the timing profile of each path differs measurably. An attacker submitting adaptively chosen ciphertexts distinguishes four outcomes: invalid RSA padding, valid padding with an incorrect key length, correct length with a wrong key, and successful decryption. This distinction implements a classical Bleichenbacher oracle [CWE-208] against RSA PKCS#1 v1.5, enabling stepwise recovery of the underlying session key.
Root Cause
The root cause combines two factors. First, the caller-visible error surface distinguishes RSA padding failures from downstream AES/PKCS#7 failures. Second, on OpenSSL 3.0, 3.1, LibreSSL, and BoringSSL, the linked library does not implement implicit rejection, so the underlying RSA operation itself signals padding validity to the caller. RFC 3218 prescribes substituting a random key on failure to eliminate this distinction, which the pre-patch code did not do.
Attack Vector
Exploitation requires a network-reachable service that automatically decrypts untrusted EnvelopedData addressed to a victim certificate and reflects the outcome, whether through explicit error responses, status codes, or observable timing. S/MIME gateways and mail filters are the canonical targets. The attacker submits a high volume of adaptively modified ciphertexts, observes per-request outcomes, and reconstructs the RSA-encrypted content-encryption key.
.. note:: This version is not yet released and is under active development.
+* **SECURITY ISSUE**:
+ :func:`~cryptography.hazmat.primitives.serialization.pkcs7.pkcs7_decrypt_der`
+ and its PEM and S/MIME variants no longer expose distinguishable errors or
+ timing when unwrapping a ``RecipientInfo``'s ``encryptedKey``, which could
+ act as a Bleichenbacher oracle for callers that decrypt untrusted messages.
+ A random key is now substituted on failure, as described in :rfc:`3218`.
+ Credit to **@X1AOxiang** for reporting the issue
Source: GitHub Commit 53fccd9. The patch substitutes a random key on failure per RFC 3218, equalizing the decryption path regardless of RSA padding outcome.
Detection Methods for CVE-2026-69247
Indicators of Compromise
- High-volume, repetitive submissions of PKCS#7 EnvelopedData messages to S/MIME gateways or mail filters from a single source
- Bursts of decryption failures on inbound application/pkcs7-mime traffic addressed to a single victim certificate
- Latency variance patterns in decryption responses consistent with distinguishing RSA padding validity
Detection Strategies
- Inventory Python environments and identify installations of cryptography at versions 44.0.0 through 49.x using pip list or software composition analysis tooling
- Alert on unusual request rates against mail filters, S/MIME endpoints, or any service invoking pkcs7_decrypt_der, pkcs7_decrypt_pem, or pkcs7_decrypt_smime on untrusted input
- Correlate decryption error logs with source IP reputation to surface adaptive-query patterns characteristic of Bleichenbacher attacks
Monitoring Recommendations
- Instrument PKCS#7 decryption code paths to log aggregate failure counts per source without exposing granular error causes to callers
- Track response-time distributions on decryption endpoints and flag statistically anomalous timing skew per client
- Monitor OpenSSL and LibreSSL versions linked by Python environments to identify libraries lacking RSA implicit rejection
How to Mitigate CVE-2026-69247
Immediate Actions Required
- Upgrade the cryptography package to version 50.0.0 or later across all Python environments
- Audit applications that call pkcs7_decrypt_der, pkcs7_decrypt_pem, or pkcs7_decrypt_smime on untrusted input and disable automatic decryption where feasible
- Rate-limit and authenticate submitters on any service that decrypts inbound EnvelopedData to reduce adaptive-oracle throughput
Patch Information
The issue is fixed in cryptography 50.0.0. The fix, tracked in pyca/cryptography PR #15369 and merged in commit 53fccd9, substitutes a random key on RSA decryption failure as specified in RFC 3218. See the GHSA-g6cj-pr64-35w5 advisory for the coordinated disclosure record.
Workarounds
- Avoid decrypting attacker-supplied EnvelopedData; upstream documentation now warns that PKCS#7 EnvelopedData does not authenticate its content and cannot be safely decrypted from untrusted sources
- Suppress differentiated error responses and normalize response timing on any endpoint that must decrypt untrusted PKCS#7 messages
- Link against an OpenSSL version that implements RSA implicit rejection (OpenSSL 3.2 or later) to reduce oracle fidelity while patching
# Upgrade the cryptography package to the fixed release
pip install --upgrade 'cryptography>=50.0.0'
# Verify installed version
python -c "import cryptography; print(cryptography.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

