**A certificate authority's private key was the number 4. Your curl still trusts it.**
CVE-2026-111943: the private keys of **eight eMudhra (emSign) intermediate CAs** — chained to roots trusted by Mozilla, Microsoft, Apple and Chrome — were mis-generated. The top 376 bits of the P-384 scalars are all zeroes: the key of
Stock macOS validates against
**Fix:** update your trust stores (Ubuntu/Debian/Alpine/Fedora ca-certificates, Go 1.27.3, Node 22.23.4+, certifi 2026.10.19, rustls-webpki 0.103.16, Deno 2.9.8, Docker Desktop 4.96.2). On macOS today, strip the two affected roots from
EM OV TLS CA - G3C is literally 4. Recoverable from the **public certificate** since April 2025. Valid until 2040.
Disclosed Oct 17 by a reporter who signed *"We have a problem here - Wayne"* with all eight keys. Browsers blocked within days (Firefox/Chrome on the 17th, Apple the 19th, Microsoft the 20th). Last night, mitmproxy started **shipping the real key**: mitmproxy --emudhra signs interception certificates with it. The CVE got its number this morning.
**Browsers were saved by Certificate Transparency** — the intermediates have zero CT log entries, so CT-enforcing clients could never be attacked. Everything else is the blast radius: curl, git, Go, Java, Node, Python certifi, Rust, CI runners. Even Claude Code shipped a fix (2.1.303) — AI tooling's bundled roots were exposed too.
I ran the official self-check on my Mac this morning:
$ curl https://dv-g3b-emudhra.we-have-a-problem.com/ Your client successfully connected to the site. That's bad!
/etc/ssl/cert.pem without consuming revocation — and that file still trusts **both** paths: the emSign root and the Sectigo/AAA cross-sign.
**Run it yourself — recover a CA private key from its public certificate:**
python
from cryptography import x509 from cryptography.hazmat.primitives.asymmetric.ec import derive_private_key cert = x509.load_pem_x509_certificate(open("EM-OV-TLS-CA-G3C.crt.pem", "rb").read()) pub = cert.public_key().public_numbers() for d in range(1, 1_000_000): if derive_private_key(d, cert.public_key().curve).public_key().public_numbers() == pub: print("private key recovered: d =", d) # d = 4 — four guesses, 2 ms
/etc/ssl/cert.pem (official awk one-liner in the write-up), then re-run the self-check — a certificate error means you're safe.
Disclosure, self-checks and the full patched list: https://emudhra.we-have-a-problem.com/
Full write-up + the lab:
→ https://blog.slabb.dev/en/a-ca-private-key-was-the-number-4-your-curl-still-trusts-it-cve-2026-111943-45o4emudhra.we-have-a-problem.comeMudhra Intermediate CA CompromiseeMudhra Intermediate CA Compromise
commit 214e2fb