Skip to main content

On Saturday 17 October, a researcher demonstrated that he held the private keys to eight eMudhra intermediate certificate authorities by signing a message with every one of them. Those intermediates chain to roots trusted by Mozilla, Microsoft, Apple and Chrome. Anyone holding those keys could have issued a valid certificate for any domain on the internet, including yours.

The browser vendors moved fast. Firefox and Chrome blocked the certificates on the 17th, Apple on the 19th, Microsoft on the 20th. If you read the coverage and concluded the problem was handled, you read it as a browser story. It is not. It is a story about every other TLS client you run: your CI runners, your webhook senders, your scrapers, your package installers, your Node services calling third-party APIs. We tested ours. On Wednesday morning, three days after the certificates were revoked for key compromise, five separate TLS clients on a stock Ubuntu box accepted the compromised chain without a murmur.

TL;DR

  • Eight eMudhra intermediate CAs had their private keys recovered because the keys were generated incorrectly. All sixteen affected certificates (eight, each in an eMudhra-signed and a Sectigo cross-signed form) were revoked on 18 October 2026 with reason cACompromise.
  • The revocation is published and trivially reachable: a 796-byte CRL over plain HTTP, and an OCSP responder that answered us “revoked, cACompromise” on demand.
  • We pointed five TLS clients on an up-to-date Ubuntu 24.04 box at the live test host: curl, wget, Python’s ssl module, Node 22 and OpenSSL. All five returned success. None of them fetched the file that says the key is public.
  • Given that same CRL explicitly, OpenSSL reports error 23: certificate revoked. Without it, the identical command prints OK. The data was never the problem.
  • We then probed 100 Irish sites. On 43 of the 98 that completed a handshake, the leaf certificate publishes no OCSP URL at all. Across three observations, 65 of 98 never stapled a revocation response, so curl --cert-status fails against two thirds of the Irish web. Not one of the 98 set must-staple.

What actually broke

The cause is unusually bleak. According to the incident report, the private keys for the eight intermediates were generated incorrectly when the certificates were created in April 2025, in a way that lets anyone recover them from the public certificates. Not stolen, not phished, not exfiltrated by an intruder. Derivable, by arithmetic, from data that has been public for eighteen months.

The incident site publishes machine-readable detail, which we pulled and counted rather than taking on trust. There are sixteen affected certificate entries covering eight distinct intermediate subjects: each intermediate exists once signed by an eMudhra root and once cross-signed by Sectigo’s AAA Certificate Services. They chain to four roots in total. Every one of the sixteen carries revocation status revoked with reason ca_compromise, timestamped between 09:24 and 09:38 UTC on 18 October 2026.

There is one piece of genuine good news. The transparency logs contain no entries for these intermediates during the exposure window, which means a CT-enforcing client (Firefox, Chrome, Edge, Safari) could not have been attacked with a certificate issued from them. The clients that do not enforce CT, which is to say most of the software in your infrastructure, have no equivalent protection.

The revocation was published. We went and got it.

The compromised intermediate served by the incident’s test host carries serial A4AEE678F23362B4C0E460B772F214. Its certificate names two places to check its status: a CRL at crl.emsign.com and an OCSP responder at ocsp-b.emsign.com. We asked both.

The CRL is 796 bytes. It returned HTTP 200 over plain HTTP with no authentication, no rate limiting and no user-agent games. It is CRL number 17, issued 18 October at 09:38:46 UTC, valid until 16 April 2027. Inside it, the serial above appears with a revocation date of 18 October 09:24:32 UTC and a reason code of CA Compromise.

The OCSP responder was equally cooperative. A single query returned Cert Status: revoked, Revocation Reason: cACompromise, with a This Update timestamp of 20 October at 23:33 UTC. Both channels work, both say the same thing, and the failure in what follows is not a data availability failure.

Five clients, five accepts

The test box is an Ubuntu 24.04.3 LTS server with ca-certificates at version 20260601~24.04.1 and 121 roots in the system bundle, one of which is emSign ECC Root CA – G3. We pointed everything on it that speaks TLS at the live host serving the compromised chain, on the morning of 21 October, three days after revocation.

  • curl (system bundle): HTTP 200.
  • wget: downloaded the page.
  • Python 3 ssl with create_default_context(): handshake completed.
  • Node 22.22.0, using its own 146 bundled roots rather than the OS store: HTTP 200.
  • OpenSSL s_client: Verify return code: 0 (ok).

Five for five. Every one of those clients had, in principle, everything it needed to know better. The certificate told it where the CRL lived. The CRL was a sub-kilobyte HTTP fetch away. None of them looked, because none of them check revocation by default, and that is not a bug in any of them. It is the design.

To make the point unambiguous, we ran the same OpenSSL verification twice. With the default options, against the system trust store, the chain verifies: OK. Hand the identical command the CRL we downloaded, with -crl_check, and it returns error 23 at 0 depth lookup: certificate revoked. Same binary, same certificates, same machine, ninety seconds apart. The only variable was whether anyone bothered to fetch 796 bytes.

The one that failed, failed for the wrong reason

The incident site exposes a second test host, serving the Sectigo cross-signed version of the same intermediate. Our clients rejected that one, which looks reassuring until you read the error. OpenSSL reports Verify return code: 20 (unable to get local issuer certificate); Node says UNABLE_TO_GET_ISSUER_CERT_LOCALLY.

That is a chain-building failure, not a revocation decision. We checked the system bundle: AAA Certificate Services is not in it at all, having been removed from the Mozilla set for entirely unrelated reasons. The server sends only the leaf and the intermediate, so there is no path to a root this box has ever heard of. The connection fails by accident.

This is the part worth internalising. Half the compromised chains were rejected by our stack, and the rejection carried no information about the compromise. An engineer seeing that error would have investigated a missing intermediate, fixed the chain and moved on feeling productive. “It errored, so we must be protected” is not a conclusion the error supports.

The fix existed. Our package manager had not noticed.

Ubuntu published a patched ca-certificates for this incident. We checked the archive directly rather than guessing: version 20260816ubuntu0.24.04.1 went into noble-security on 20 October and noble-updates on 21 October. It is real, it is out, and the maintainers were quick.

On our box, apt-cache policy ca-certificates offered a candidate of 20260601~24.04.1, which is also what was installed. The local package index simply predated the publication. There was no newer version to install as far as that machine was concerned, and an apt-get upgrade in a cron job would have reported nothing to do.

That gap, between a fix being published and a host’s view of the archive catching up, is where the exposure lives. It is measured in hours or days, it is invisible unless you look, and no alert fires when you are on the wrong side of it. For the clients that carry their own roots there is nothing to patch at all: Node ships its own 146-certificate store, so an OS update would not have helped it, which is why the incident’s own compatibility table still listed Node as pending when we ran these tests.

So we asked whether the Irish web can be checked at all

The eMudhra case is a compromised intermediate, which is the scenario revocation infrastructure exists for. We wanted to know how much of that infrastructure is actually reachable on real production sites, so we took a list of 100 Irish domains (news, retail, banking, utilities, government, property) and inspected what each one’s certificate chain offers a client that genuinely wants to verify status.

Ninety-eight completed a TLS handshake. Two, an-post.ie and welfare.ie, did not complete under our probe and are excluded from the percentages below rather than counted as failures.

43 of 98 leaf certificates publish no OCSP URL at all. There is no responder to ask. That is not negligence by the site operators; it is the direct consequence of the industry retiring OCSP. The breakdown by issuer is clean: all 16 Google Trust Services certificates, all 15 Let’s Encrypt certificates, 8 of 10 GlobalSign, plus a handful of others. The 55 that do publish one come overwhelmingly from DigiCert (25), Amazon (16) and Sectigo (8).

65 of 98 never stapled a revocation response. We observed stapling three separate times across three separate runs. 28 sites stapled on every observation, all reporting status good. 33 stapled on at least one. The remaining 65 sent nothing, every time.

curl --cert-status fails against 65 of 98 Irish sites. This is the one revocation flag most engineers reach for, and we ran it for real rather than inferring it: 33 succeeded, 64 failed with curl: (91) No OCSP response received, and one failed with a certificate error. If you harden a service by adding that flag, you have just broken two thirds of your outbound Irish traffic.

Not one of the 98 sets must-staple. Zero. The extension that would let a site insist its revocation status be presented on every connection is used by nobody in the sample.

Two further numbers are worth sitting with. First, stapling is not a stable property of a site: two domains changed their answer between our two stapling runs, which means a single check tells you what one edge node did on one connection, not what the site does. Second, and more pointedly for this incident, 36 of 98 chains have no intermediate that publishes an OCSP URL, so the exact failure mode in the news this week is not checkable by OCSP on more than a third of the chains we looked at.

There is one genuinely encouraging result. Every single chain, 98 of 98, has intermediates that publish a CRL distribution point. The information is universally available. It is simply that outside a browser, essentially nothing fetches it.

Certificate lifetimes in the sample ran from 7 days to 731, median 197. Short lifetimes are the industry’s real answer to revocation, and a decent one for leaf certificates. They do nothing for a compromised intermediate valid until 2040.

What we would actually do about it

Revocation checking is not something you switch on globally without breaking things, and anyone who tells you otherwise has not measured it. Our advice is narrower and more useful.

Know which trust stores you run, not just how many servers. A patched OS does not patch Node, Python environments that bundle their own certifi, Go binaries compiled with embedded roots, JVM cacerts, or container images built from a base you last rebuilt in August. Inventory the stores. The number is always higher than people expect.

Alert on the age of the trust store, not on patch success. The failure mode here was not “the update failed”, it was “there was no update to apply yet”. A check that reports the installed ca-certificates version and its age catches this; a check that reports whether apt-get upgrade exited zero does not.

Rebuild base images on CA events, not on a schedule. A root programme incident is a rebuild trigger in the same way a kernel CVE is. If your pipeline cannot rebuild and redeploy every image within a day of a trust store update, that interval is your exposure window, and this week it was three days long for us.

Apply strict revocation checking where it is cheap and you control both ends. Service-to-service calls inside your own estate, or to a known small set of partner APIs, can reasonably run with CRL or OCSP checking enforced, because you can verify in advance that the endpoints support it. Our 65-of-98 figure is the argument against doing it to the open web, not against doing it anywhere.

Treat Certificate Transparency monitoring as the control that actually worked. CT is what let the world say with confidence that browser users were not attacked during an eighteen-month exposure. Monitoring CT logs for certificates issued against your own domains is cheap, it is the control with the best track record in this incident, and most organisations still do not do it.

None of this is exotic. It is inventory, alerting thresholds and rebuild triggers: DevOps work that loses budget arguments to feature delivery right up until a week like this one. Three days of silent trust in a CA with a public private key is cheap to prevent and expensive to explain.

At REPTILEHAUS we build and operate this layer for clients: trust store inventories, CI and container pipelines that rebuild on upstream security events, and the monitoring that tells you the age of what you are trusting rather than whether a cron job exited cleanly. If you cannot currently answer how many distinct root stores your production estate depends on, that is the question worth starting with. Get in touch and we will help you work it out.

Methodology: all figures measured first-hand on 21 October 2026. Client tests ran against the incident’s published test hosts from an Ubuntu 24.04.3 LTS server. The Irish sample is 100 domains probed with OpenSSL s_client, of which 98 completed a handshake; stapling was observed across three independent runs. Revocation data was retrieved directly from the CA’s published CRL and OCSP responder, and patch availability was confirmed against the Ubuntu archive rather than taken from secondary reporting.

📷 Photo by Markus Spiske on Unsplash