eMudhra's private key was the number 4, and your command line may still trust it

Eight eMudhra intermediate CA keys were small enough to guess. Browsers blocked them within hours and Chrome drops the root on 27 October. Curl, old Go builds and stale trust stores are where the risk now sits.

Share
eMudhra's private key was the number 4, and your command line may still trust it

A P-384 private key is supposed to be a random number about 115 digits long. For eight certificate authorities that every major browser trusted until 17 October, the private key was a number below 256. One of them was 4.

Anyone who knows the trick can recover a key like that faster than they can boil a kettle, and with it sign a certificate for any website on the internet. The browsers dealt with it inside a day, but the rest of your software is another matter, and if you run VPN or proxy tooling from a terminal, that is where you should be looking this week.

What went wrong

The keys belonged to eight intermediate certificates operated by eMudhra, an Indian certificate authority: six for TLS and two for code signing, all issued under its emSign ECC Root CA - G3 and also cross-signed by Sectigo, which gave them a second route to trust.

Mozilla's incident bug states it plainly: "The 8 impacted keys all used integers less than 256", which leaves each key "effectively all-zeroes apart from the last byte". Mozilla recovered them independently in under two hours, by trying every value. An independent analysis did the same and published the results: the key for "EM OV TLS CA - G3C" is 4, and the other seven fall between 56 and 237. The method is reproducible by anyone with a maths library and a minute to spare.

Try every private key from 1 to 255 against the intermediate's public key; for EM OV TLS CA - G3C it is 4, which lets anyone sign a certificate for any domain.
With only 255 possible keys, recovering one takes seconds.

eMudhra's preliminary explanation, given in the bug, is that a flaw in its key-ceremony script on 30 April 2025 created a second, weak set of keys on the hardware security module during an approved test, and that those keys were used by mistake because their labels looked similar to the real ones. So the flaw sat in the web's trust infrastructure for nearly 18 months. eMudhra says only one of the eight was ever in production and that it issued no end-entity certificates.

Why one weak intermediate is enough

An intermediate CA with the TLS server purpose and no name constraints can sign a certificate for any domain, and every client that trusts its root will accept it. None of these eight had name constraints.

The attack that follows is an old one, and it still works. Someone on the path between you and a server, such as a hostile Wi-Fi operator, an ISP or a state, presents a certificate for the real domain signed by the compromised intermediate. Your client sees a valid chain, completes the handshake and talks to the interceptor, which relays to the real server so that nothing visibly breaks. Governments that want to read traffic have spent years trying to get citizens to install a state root certificate for exactly this purpose. A trusted public intermediate saves them the trouble.

There is no evidence anyone used these keys. Google says no TLS certificate chaining to the compromised CAs appeared in Certificate Transparency logs before its block. That is reassuring for browsers, which enforce CT. It says less about clients that don't check CT, because an attacker targeting those would never log anything.

The browsers moved quickly

Google's Chrome Root Program received the report at 18:05 UTC on Saturday 17 October and pushed a block of the eight public keys through CRLSet, Chrome's revocation list, at 19:45 UTC. Blocking by key also catches the Sectigo cross-signed copies. Mozilla had the keys recovered by 21:48 UTC and blocked in Firefox's OneCRL shortly after. eMudhra revoked all eight on the morning of 18 October and Sectigo revoked its cross-signatures. Android received the block through Google Play Services on the evening of 19 October, and a restart pulls it immediately. Apple has blocked the intermediates on its devices since the same day, and Microsoft has pushed blocks through its automatic trust-list updates.

The next date is Tuesday 27 October, when Chrome removes emSign ECC Root CA - G3 from its root store altogether; Firefox has already done so. The removal will break legitimate sites, as eMudhra estimates around 30,000 certificates still chain to that root and need replacing. Most were issued through ACME, so if you run a site or panel with an eMudhra certificate, check it now.

If you use a current Chrome, Firefox or Safari, you were protected within a day or two.

Who is still exposed

Revocation only protects clients that check it, and most software outside browsers doesn't. Command-line tools and libraries usually trust a bundle of root certificates on disk and never ask whether an intermediate has been revoked. Until that bundle changes, these intermediates are as trusted as they were on 16 October.

The volunteer-run disclosure site tracks fixes. At the time of writing it lists patched packages for Debian, Ubuntu, Fedora, Alpine, Arch, Gentoo and FreeBSD, plus Python's certifi 2026.10.19, pip 26.2.2, rustls-webpki 0.103.16, webpki-roots 1.0.10, Electron, Deno, Composer and the curl CA bundle of 20 October. Node.js shipped its fix in 22.23.4, 24.22.1 and 26.12.1 on 21 October, alongside an unrelated batch of security fixes. Bun and Bottlerocket are still pending.

Two cases deserve a closer look.

Go. Go 1.27.3 and 1.26.10, released on 20 October, add a hard denylist for the eight keys to the certificate verifier. It catches the Sectigo cross-signed copies, applies even when a program brings its own trusted roots, and can't be switched off. It is also compiled in, which means a Go binary built with an older toolchain keeps trusting whatever its root store trusts. Updating ca-certificates removes the emSign root, but the cross-signed path leads to a different root, and only the denylist or an explicit block closes it.

macOS. The operating system blocks the intermediates, but the built-in /usr/bin/curl reads its own file, /etc/ssl/cert.pem, which Apple has not updated, and doesn't check revocation. The Mac's own curl therefore still trusts them.

Older Android phones that no longer get Play Services updates, Java runtimes with their own trust stores and embedded devices make up the long tail. Some of them will never be fixed.

A forged certificate is rejected only by clients that block the eight keys; others accept it because the Sectigo cross-signed chain still reaches a trusted root.
Updating your root bundle isn't enough. Only blocking the keys closes both paths.

What it means for VPN and proxy users

It depends on how your client decides it is talking to the right server.

REALITY is not affected by a forged certificate. Xray's REALITY client does not take a public CA's word for the server's identity; it checks a signature tied to the server key you configured. An interceptor holding an eMudhra key can mint a flawless certificate for your cover site and still fail that check.

VLESS, Trojan or VMess over ordinary TLS are exposed if the client was built with a Go older than 1.26.10 or runs on a system with a stale root bundle. Such a client will accept a certificate from these intermediates for your server's domain. A client set to allowInsecure was already accepting anything, so it is no worse off, which is not much of a defence.

WireGuard, AmneziaWG and OpenVPN with your own CA are untouched. They authenticate with keys or a private CA you control.

Subscription URLs, update checks and panels are exposed. Many clients fetch their server list over HTTPS from a panel. A fetcher that trusts a stale bundle can be handed a forged list, which is a quieter attack than intercepting the tunnel and arguably a more useful one.

For censorship, the window is narrow but real. A state would need clients that trust the old roots and skip revocation, and it would need to act before updates land. Browsers are out of reach, but old phones, routers and unpatched command-line tools are not, and a network operator can see which of those it carries.

The other Node.js fix in that release

The same Node.js release also fixes an unrelated bug that matters more to some readers than eMudhra does. CVE-2026-111497, rated High, is an out-of-bounds write in Node's Brotli decoder: feed it hostile compressed data and the process can leak memory or, in the worst case, run the attacker's code. You don't have to call a decompression function yourself to be exposed. As Aikido points out, Node's built-in fetch() and common middleware such as body-parser decompress Brotli for you.

That makes Node-based subscription converters and dashboards the obvious case for this site's readers: their whole job is to fetch configuration from URLs someone else controls, or to accept data posted to them. If you run one, the Node upgrade below is not just about trust stores.

The verdict

eMudhra failed at the only job a certificate authority has, and the browser makers cleaned up after it within hours. Their revocation machinery works, but the incident is a reminder of how much software never consults it, and that gap is precisely where a key like this would be used.

What to do

  1. Test each machine: run curl https://dv-g3b-emudhra.we-have-a-problem.com/ and curl https://dv-g3b-aaa-emudhra.we-have-a-problem.com/ from every server, container and workstation that runs your proxy, panel or VPN tooling. These hosts use certificates under the compromised intermediates; the second tests the Sectigo cross-signed path. A certificate error is the result you want; a page that loads means that client still trusts them.
  2. Update trust stores: ca-certificates, certifi and the operating system, and move Node to 22.23.4, 24.22.1 or 26.12.1.
  3. Check your Go binaries by running go version -m on each proxy core and tool you didn't build yourself. Anything built with Go older than 1.26.10, or 1.27.0 to 1.27.2, lacks the denylist. If a release you depend on was built before 20 October, wait for a rebuild or build it yourself.
  4. On a Mac, use Homebrew's curl rather than /usr/bin/curl for anything sensitive until Apple updates /etc/ssl/cert.pem.
  5. If you serve a site on an eMudhra certificate, replace it before 27 October, or Chrome users will see an error.
  6. In proxy configs, prefer REALITY or key-pinned transports, never use allowInsecure, and pin your subscription panel's certificate where the client allows it.

If you only have time for one of these, make it the curl test. It takes seconds per machine and tells you more than any changelog.