Aug 4, 2026·7 min read·359 visits
A Bleichenbacher side-channel timing and error oracle in pyca/cryptography before version 50.0.0 allows unauthenticated remote attackers to recover Content Encryption Keys (CEK) and decrypt sensitive S/MIME messages by submitting crafted PKCS#7 ciphertexts and observing decryption responses.
A side-channel vulnerability in pyca/cryptography (versions 44.0.0 through 49.9.9) allows unauthenticated remote attackers to expose a Bleichenbacher oracle. This flaw exists within the PKCS#7 decryption module (specifically pkcs7_decrypt_der, pkcs7_decrypt_pem, and pkcs7_decrypt_smime) during Content Encryption Key (CEK) decryption when using RSA PKCS#1 v1.5 padding. Differences in error classification and symmetric execution timing allow an attacker to reconstruct plaintext keys.
The library pyca/cryptography is the primary cryptographic implementation layer for the Python ecosystem. In versions 44.0.0 through 49.9.9, the module responsible for parsing and decrypting PKCS#7 / CMS (Cryptographic Message Syntax) EnvelopedData payloads suffers from a classic side-channel leakage vulnerability. Specifically, when decrypting the encrypted symmetric Content Encryption Key (CEK) packaged inside a RecipientInfo structure, the application behaves differently depending on the decryption outcome of the RSA PKCS#1 v1.5 cipher block.
This behavior exposes a Bleichenbacher oracle (CWE-208 / CWE-209). If a remote application—such as an automated S/MIME email gateway, secure mail filter, or backend document processing system—automatically processes untrusted incoming PKCS#7 envelopes using a resident private key, it risks disclosing the decrypted CEK to an active network attacker. This bypasses the confidentiality guarantees expected of RSA-wrapped symmetric transport layers.
The vulnerability is highly dependent on the underlying cryptographic backend's handling of padding validation. When linked against libraries that do not enforce implicit rejection of invalid PKCS#1 v1.5 padding (such as OpenSSL 3.0, OpenSSL 3.1, LibreSSL, or BoringSSL), the python-level implementation fails to unify error behaviors. This creates distinct logical branches that an attacker can measure remotely.
The fundamental defect in src/rust/src/pkcs7.rs stems from the sequential, non-constant-time manner in which the PKCS#7 decryption pipeline is executed. When processing an EnvelopedData envelope, the library must decrypt the RSA-wrapped encryptedKey to extract the raw symmetric CEK (typically an AES-128 or AES-256 key), verify the algorithm identifier parameters, and then initialize the symmetric block cipher to decrypt the actual ciphertext payload.
Prior to version 50.0.0, the library executed these steps in a linear, unguarded order. This logical sequence produced four distinguishable outcomes depending on the structure of the attacker-supplied encryptedKey:
Invalid RSA Padding: If the private key decryption failed due to malformed PKCS#1 v1.5 padding, a ValueError exception was immediately raised. The process terminated before symmetric cipher initialization.
Incorrect Key Size: If the RSA decryption succeeded, but the extracted plaintext byte sequence did not match the expected key size of the target symmetric algorithm (e.g., 17 bytes instead of the expected 16 bytes for AES-128-CBC), the initialization of the AES algorithm object aborted with an explicit 'Invalid key size' exception. This leaked the exact length of the decrypted plaintext block.
Incorrect Symmetric Key with Correct Size: If the decrypted plaintext key had the correct length but was incorrect, the symmetric cipher initialized successfully. However, the subsequent AES-CBC decryption phase failed during PKCS#7 unpadding of the symmetric payload. This raised a CBC padding error.
Correct Key: Decryption completed successfully without error.
Because the early-abort scenarios (1 and 2) exit prior to the resource-intensive AES-CBC decryption phase, they take significantly less processing time than scenario 3. An attacker can supply a very large encrypted symmetric payload to dramatically amplify this timing delta, establishing a highly reliable timing oracle alongside the distinguishable error messages.
An analysis of the vulnerable implementation in src/rust/src/pkcs7.rs reveals how the early aborts bypassed the uniform error-handling logic. The vulnerable code executed RSA decryption using PyO3 bindings directly before looking up the required symmetric key length:
// VULNERABLE CODE PATH
let key = match recipient_info.key_encryption_algorithm.oid() {
&oid::RSA_OID => {
let padding = types::PKCS1V15.get(py)?.call0()?;
private_key
.call_method1(
pyo3::intern!(py, "decrypt"),
(recipient_info.encrypted_key, &padding),
)?
.extract::<pyo3::pybacked::PyBackedBytes>()?
}
_ => { /* ... error ... */ }
};
let algorithm_identifier = enveloped_data
.encrypted_content_info
.content_encryption_algorithm;
let (algorithm, mode) = match algorithm_identifier.params {
AlgorithmParameters::Aes128Cbc(iv) => (
types::AES128.get(py)?.call1((key,))?, // Key length check occurs here
// ...
),
// ...
};If private_key.call_method1 raised a PyValueError due to bad RSA padding, the execution aborted immediately. Similarly, if the key length was incorrect, the call to AES128 raised an exception.
The patch in version 50.0.0 implements the RFC 3218 mitigation standard. It extracts the expected key length before RSA decryption, generates a cryptographically random fallback key of that exact size, and executes the RSA decryption in a protected match block. If RSA decryption fails or yields an incorrect key length, the random key is silently substituted:
// PATCHED CODE PATH
let padding = types::PKCS1V15.get(py)?.call0()?;
let random_key = crate::backend::rand::get_rand_bytes(py, key_size)?;
let key = match private_key.call_method1(
pyo3::intern!(py, "decrypt"),
(recipient_info.encrypted_key, &padding),
) {
Ok(key) => {
let key = key.extract::<pyo3::Bound<'_, pyo3::types::PyBytes>>()?;
if key.as_bytes().len() == key_size {
key
} else {
random_key
}
}
Err(e) if e.is_instance_of::<pyo3::exceptions::PyValueError>(py) => random_key,
Err(e) => return Err(e.into()),
};By ensuring that a random key of the correct size is utilized when decryption fails or the size is invalid, the code forces the pipeline to continue execution through the symmetric AES-CBC decryption phase. This equalizes the execution path and eliminates the timing discrepancy.
To exploit this vulnerability, an attacker must have network access to an interface or service that processes user-supplied PKCS#7 envelopes and returns either direct error feedback or measurable timing differences. S/MIME mail gateways and secure email filters are primary targets, as they automatically decrypt incoming encrypted messages using local server certificates.
The attack begins with the generation of modified PKCS#7 ciphertexts. The attacker targets the encrypted_key field (the wrapped CEK) of a captured or intercepted EnvelopedData payload. Following the classical Bleichenbacher algorithm, the attacker applies mathematical modifications to the ciphertext, multiplying the encrypted integer representation by chosen values ($s$).
The modified PKCS#7 structures are then transmitted to the target service. The attacker monitors the response:
By systematically evaluating the oracle's responses across several thousand to millions of adaptive queries, the attacker narrows down the mathematical range of the plaintext CEK until it is fully reconstructed. Once the CEK is recovered, the attacker can decrypt the associated symmetric payload, compromising the confidentiality of the entire message archive.
A successful Bleichenbacher oracle attack results in a complete loss of confidentiality for the encrypted symmetric payload. If an attacker can query the decryption oracle successfully, they can decrypt any historic or newly intercepted message encrypted for the targeted recipient's certificate without possessing the private key.
In CVSS v4.0, this vulnerability receives a rating of 8.2 (High). The vector string is 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. The High Attack Complexity (AC:H) and Present Attack Requirements (AT:P) reflect the necessity of a timing-stable, high-volume query channel and an automated processing endpoint.
There is currently no evidence of active exploitation in the wild, and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, because pyca/cryptography is deeply integrated into many popular Python libraries, web frameworks, and corporate mail gateways, the actual attack surface is extensive. Services that process S/MIME mail or encrypted medical data are at the highest risk.
The primary remediation step is upgrading the python-cryptography library to version 50.0.0 or later. This introduces the RFC 3218-compliant key substitution mitigation, making RSA decryption failures indistinguishable from symmetric decryption failures.
Security engineers must evaluate whether their downstream runtime environments utilize custom or hardware-based cryptographic engines (HSMs). Because the patched code explicitly filters on pyo3::exceptions::PyValueError, any provider that throws a custom exception class on decryption failure will bypass the error-catching logic. This would propagate the exception immediately to the caller and re-expose the Bleichenbacher oracle. Ensure that any external backends conform to standard Python exception structures.
Additionally, applications must treat PKCS#7 EnvelopedData as inherently unauthenticated. As noted in the updated library documentation, even with the Bleichenbacher oracle patched, PKCS#7 does not natively authenticate its contents. Any service that reveals whether symmetric decryption succeeded or failed—through status codes, database side effects, or distinct error messages—remains vulnerable to standard symmetric padding oracle attacks. Design systems to avoid decrypting untrusted, unauthenticated EnvelopedData in synchronous, user-exposed flows.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
cryptography pyca | >= 44.0.0, < 50.0.0 | 50.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-208: Observable Timing Discrepancy |
| Attack Vector | Network (AV:N) |
| CVSS v4.0 Score | 8.2 (High) |
| Exploit Status | Proof of concept code exists in library test suites; no public weaponized exploits. |
| CISA KEV Status | Not listed |
| Mitigation Standard | RFC 3218 (Key substitution on failure) |
| Affected Functionality | pkcs7_decrypt_der, pkcs7_decrypt_pem, pkcs7_decrypt_smime |
The system performs a cryptographic operation that takes a variable amount of time depending on the input values, leading to an observable timing discrepancy.
CVE-2026-16454 is an object-level authorization bypass vulnerability (CWE-284, CWE-862) in Eclipse hawkBit versions 1.0.3 and prior. The flaw exists within the Direct Device Integration (DDI) REST controller (hawkbit-ddi-resource), where endpoints responsible for enumerating software module metadata and serving firmware binaries fail to verify whether the requested software module is assigned to the authenticated device. Consequently, any device with valid credentials (such as a TargetToken or GatewayToken) can enumerate software module identifiers and download arbitrary firmware artifacts across the entire tenant namespace.
CVE-2026-62284 (GHSA-5w5g-j6hw-6p8f) is a code injection and server-side request forgery vulnerability in the console-proxy component of the OSAC Operator. The RemoteConfigResolver parses Kubernetes Secrets containing kubeconfig files via clientcmd.RESTConfigFromKubeConfig without sanitizing execution-related fields. An attacker with RBAC permissions to create or modify labeled Secrets in monitored namespaces can supply a malicious exec credential plugin, resulting in arbitrary command execution within the console-proxy pod.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.