Feb 10, 2026·6 min read·278 visits
Missing validation in `pyca/cryptography` allowed attackers to force operations into small subgroups on binary curves (SECT), leading to private key recovery via the Chinese Remainder Theorem.
A high-severity flaw in the standard Python `cryptography` library allows attackers to recover private keys when using binary elliptic curves. By exploiting missing subgroup validation, malicious actors can perform Small Subgroup Attacks to leak private key bits via ECDH key exchange.
If you are writing Python and you need to encrypt something, you don't roll your own crypto (unless you have a death wish). You use pyca/cryptography. It is the bedrock of the Python ecosystem, underpinning giants like Ansible, Paramiko, and seemingly every secure web framework in existence. It promises 'cryptographic recipes and primitives' that are safe by default. Ideally, it hides the foot-guns of OpenSSL behind a nice, rusty memory-safe abstraction.
But even the sharpest tools get dull. CVE-2026-26007 isn't a memory corruption bug or a buffer overflow; it's a logic failure in the mathematical plumbing of Elliptic Curve Cryptography (ECC). Specifically, the library forgot that not all points on a curve are created equal. By failing to check if a public key belongs to the safe part of the curve, the library opened the door to a classic cryptographic attack we thought we'd left in the 90s.
This vulnerability specifically targets binary curves (the SECT family). While modern cryptographers largely ignore these in favor of prime curves (like P-256 or Curve25519), legacy systems in banking and government still rely on them. If you're one of those unfortunates, your private keys might not be private anymore.
To understand this bug, we have to talk about the shape of an elliptic curve. A curve forms a group of points. The total number of points is called the order ($N$). For a curve to be cryptographically useful, we want to work in a subgroup of prime order ($n$). Ideally, $N = n$. This is true for prime curves like NIST P-256.
However, binary curves (like SECT283K1) have a property where the total points $N$ is not prime. Instead, $N = h \cdot n$, where $h$ is a small integer called the cofactor. Usually, $h$ is 2 or 4. This means the curve contains the massive prime subgroup we want to use, but it also contains tiny, parasitic subgroups of order $h$ (and divisors of $h$).
The vulnerability is simple: pyca/cryptography checked if a point was on the curve, but it didn't check if the point was in the correct subgroup.
Imagine a club (the Curve) with a VIP section (the Prime Subgroup) and a broom closet (the Small Subgroup). The bouncer (the library) was checking tickets to see if people belonged in the club, but forgot to stop people from sneaking into the broom closet. If an attacker forces your cryptographic operations into the broom closet, the math breaks down because the space is too small to hide secrets.
The flaw lived in the Rust backend of the library (src/rust/src/backend/ec.rs). When loading a public key, the library would defer to OpenSSL. However, it wasn't being paranoid enough about the inputs.
Here is the logic prior to the fix. It essentially trusted that if the point coordinates satisfied the curve equation, everything was fine:
// PRE-PATCH PSEUDOCODE
// We have coordinates (x, y)
let point = EC_POINT_new(group);
EC_POINT_set_affine_coordinates(group, point, x, y, ...);
// As long as it's on the curve, we are good to go.
if EC_POINT_is_on_curve(group, point, ...) {
return Ok(point);
}The fix, authored by Paul Kehrer and Alex Gaynor in commit 0eebb9dbb6343d9bc1d91e5a2482ed4e054a6d8c, introduces a strict check on the cofactor. If the curve has a cofactor greater than 1, it forces a full key check:
// THE FIX (Commit 0eebb9d)
let mut cofactor = openssl::bn::BigNum::new()?;
ec.group().cofactor(&mut cofactor, &mut bn_ctx)?;
let one = openssl::bn::BigNum::from_u32(1)?;
// If cofactor != 1, we MUST verify the order
if cofactor != one {
// This calls OpenSSL's EC_KEY_check_key which verifies n * P = Infinity
ec.check_key().map_err(|_| {
pyo3::exceptions::PyValueError::new_err(
"Invalid EC key (key out of range, infinity, etc.)",
)
})?;
}> [!NOTE]
> Why not check every time?
> Performance. Full validation (check_key) involves scalar multiplication, which is expensive. Prime curves (cofactor=1) don't need this check because they don't have small subgroups.
How do we weaponize this? We use a Small Subgroup Attack (specifically a Lim-Lee style attack). This is most devastating in Elliptic Curve Diffie-Hellman (ECDH).
The Setup:
The Attack Chain:
The Finale: The attacker repeats this process with points of order 17, 19, 23, etc. Once they have collected enough congruences ($d \pmod{k_i}$), they use the Chinese Remainder Theorem (CRT) to stitch them together and recover the full private key $d$.
It is like guessing a combination lock number. Instead of guessing 1,000,000 possibilities, you figure out the last digit, then the second to last, and so on, until the door opens.
If you are using NIST P-256, P-384, or P-521, you can relax. These are prime curves with a cofactor of 1. You are immune by design.
However, if you are working in environments that mandate Binary Curves (e.g., SECT571K1, SECT283R1), this is a critical severity issue. These curves are often found in:
For these users, an attacker can passively recover long-term private keys. Once the key is gone, the attacker can decrypt past traffic (if no forward secrecy was used) or impersonate the server indefinitely. The only saving grace is the complexity: the attacker needs to perform multiple handshakes to extract the full key.
The immediate remediation is simple: Upgrade to cryptography version 46.0.5. This version includes the Rust-side fix that explicitly validates group order for curves with cofactors.
But the developers of pyca/cryptography went a step further. They aren't just patching the hole; they are condemning the building. In this release, all SECT curves have been deprecated.
This is a clear signal from the maintainers: Binary curves are dangerous, brittle, and rarely used in modern stacks. The ultimate fix is to migrate your infrastructure to Curve25519 or P-256. If you are still using SECT curves in 2026, you have bigger architectural problems than just this CVE.
CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
cryptography pyca | < 46.0.5 | 46.0.5 |
| Attribute | Detail |
|---|---|
| CWE | CWE-345 (Insufficient Verification of Data Authenticity) |
| CVSS v4.0 | 8.2 (High) |
| Attack Vector | Network |
| Attack Complexity | High (Requires specific curve usage) |
| Privileges Required | None |
| Impact | Private Key Extraction |
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.