Your Trust Store Is Infrastructure: What the eMudhra CA Compromise Exposed
On 17 October a researcher reported that eight eMudhra intermediate certificate authorities had private keys anyone could recover from the public certificates. Mozilla recovered the keys itself less than two hours after the report reached it, according to CSO Online . Google said the keys were generated with “insufficient randomness”. Scott Helme recovered all eight in under a second, and some of the values were as small as 4, 56 and 115. Six of the intermediates issued TLS certificates and two issued code-signing certificates.
Anyone holding those keys can mint a certificate for any domain that chains to a trusted root. Your browser stopped trusting them within days. Much of your estate still trusts them today.
The browsers moved fast
The vendors that control their own trust decisions acted quickly:
- Chrome pushed a CRLSet update that blocked the intermediates without a browser update or restart. Android and ChromeOS received the same block through Google Play Services. Google also removed the emSign ECC Root CA – G3, which signed the intermediates, from the Chrome Root Store with effect from today, 27 October.
- Firefox blocked the certificates through OneCRL.
- Apple began blocking the TLS intermediates on 19 October and the emSign root on 23 October, according to its support notice .
- Microsoft has blocked them through its disallowed certificate list since 20 October, as Veeam’s support statement records.
All four rely on machinery that most organisations never touch: revocation lists pushed by the vendor, and Certificate Transparency checks. That machinery stops at the edge of the browser and the operating system’s own networking stack.
Where the browser’s protection ends
Apple’s notice is unusually candid about the gap. Safari, Mail and apps built on Apple’s networking frameworks are covered. Command-line tools that read /etc/ssl/cert.pem, including curl, git, python3, ruby, perl and openssl, “don’t check Apple’s block or whether the certificate has been revoked”. Apple says the file will be fixed in a future macOS update.
The same pattern runs through the rest of a typical estate. Red Sift notes that non-browser software trusts a certificate bundle on disk and mostly checks neither revocation nor CT. Its researchers built a forged certificate for a well-known payments API, and curl, Python and Node.js all accepted it by default. Each of these carries its own copy of the trust list:
- Linux hosts trust whatever the distribution’s
ca-certificatespackage contains until that package is updated. - Python applications using
requeststrust thecertifibundle. The fixed release is certifi 2026.10.19, with pip 26.2.2 and uv 0.13.4 shipping updated lists, as Simon Willison tracked. - Node.js ships a root store compiled into the binary.
- Java trusts the
cacertskeystore bundled with each JDK. - Go reads the system bundle on Linux. A scratch or distroless image carries the bundle copied in at build time, frozen until the image is rebuilt.
- Containers carry the trust store of their base image on the day they were built.
- Appliances such as backup servers, load balancers and firewalls ship their own trust store and update it on the vendor’s schedule.
One detail makes manual blocking harder. Sectigo cross-signed all eight intermediates under its AAA Certificate Services root a month after they were created, so each key appears in two certificates. Red Sift’s advice is to reject the affected keys through both chains. Deleting one cached intermediate leaves the other path open.
The PHP parallel in the same week
On 21 October the PHP project fixed two critical remote code execution flaws, CVE-2026-109618 and CVE-2026-109619, known as PHP2Shell. Help Net Security reports that every PHP installation serving web requests is affected, including PHP-FPM, mod_php, php-cgi, FrankenPHP and LiteSpeed. Amazon recorded an exploitation attempt on 17 October, four days before disclosure. The fixed releases are 8.5.12, 8.4.27, 8.3.36 and 8.2.35. PHP 8.1 and older are end of life, and the security team published source backports for 7.4, 8.0 and 8.1 for anyone building from source.
Most organisations know where their PHP websites run. Far fewer know where PHP runs inside something else. Palo Alto Networks confirmed that all PAN-OS and Panorama versions are affected, with no fixed release at the time of the report. Control panels, monitoring tools and vendor appliances embed PHP the same way they embed a trust store.
Both incidents expose the same blind spot. A runtime or a certificate bundle sits inside a product, and nobody in the organisation owns it.
A five-day response playbook
This is the sequence I would run with a small team this week.
Day 1: test the real application path. The researchers who reported the compromise publish test hosts at emudhra.we-have-a-problem.com
. The certificate for dv-g3b-emudhra.we-have-a-problem.com chains through a compromised intermediate. A successful connection means the client still trusts it. A certificate error means it is blocked. Run the test from inside the container or host that makes the real outbound calls, because your laptop proves nothing about production:
docker run --rm --entrypoint curl your-image:tag -sS -o /dev/null -w '%{http_code}\n' https://dv-g3b-emudhra.we-have-a-problem.com/
docker run --rm --entrypoint python3 your-python-image:tag -c "import requests; print(requests.get('https://dv-g3b-emudhra.we-have-a-problem.com/').status_code)"
docker run --rm --entrypoint node your-node-image:tag -e "fetch('https://dv-g3b-emudhra.we-have-a-problem.com/').then(r => console.log(r.status), e => console.log('rejected:', e.cause?.code))"
The --entrypoint flag bypasses any entrypoint script in the image. The Python line tests the certifi bundle that requests uses, so run it in images where your application uses requests; code built on urllib reads the system bundle, which the curl line already covers. The Node line needs Node 18 or later.
A 200 means that runtime needs attention. Read the error on a failure, since a DNS or proxy problem fails the same way as a rejected certificate.
I ran the same three checks on my own workstation this morning. curl and Python rejected the certificate. Node.js 24.22.0 returned 200. One machine, one owner, and one of its three trust stores was still open.
Day 2: update the bases. Apply your distribution’s ca-certificates update to hosts and base images. Bump certifi, Node.js and the JDK where they lag. On Windows servers without Windows Update access, update the disallowed certificate list by hand, as Veeam advises.
Day 3: rebuild and redeploy. Rebuild every image from the updated base, including Go services on scratch images. A patched base image protects nothing until the containers running in production are replaced.
Day 4: check the edges. Review mutual TLS, VPN, API gateway and certificate pinning configurations for the emSign root and both cross-signed chains. Patch PHP everywhere you can, and ask each appliance vendor for its PHP2Shell and eMudhra status in writing.
Day 5: decide on what cannot be fixed. End-of-life PHP and appliances without a vendor update need a decision with a named owner. Restrict their network access, put a validating gateway in front of them where possible, and record the risk acceptance with a review date. The same reasoning applies to management consoles that should never face the internet .
Making it stick in the ISMS
The response takes a week. The lesson should last longer. ISO 27001:2022 already has the controls; trust stores and runtimes are missing from their scope.
- A.5.9, inventory of information and other associated assets. Add trust stores and language runtimes to the asset register as components of the systems that contain them. Record the base image, runtime version and trust store source for each service. This morning’s post on secondary systems that escape the register makes the case for the hardware; this is the software equivalent.
- A.8.8, management of technical vulnerabilities. Treat a trust store update as a patch with an owner and a deadline. A CA incident becomes a ticket against named systems.
- A.8.24, use of cryptography. Your cryptography policy should state which trust stores each class of system relies on and how they are updated.
- A.5.21, managing information security in the ICT supply chain. Require suppliers to tell you which runtimes and root stores their products bundle, and how fast they ship updates. The third-party risk post covers how to put that into contracts.
Give each item an owner and a quarterly review. When the next CA fails, the question “where do we trust this root?” should take one query against the register.
What to ask vendors for
I want software bills of materials that list bundled runtimes and root stores as first-class components. An SBOM that names every npm package but omits the PHP interpreter and the CA bundle misses the parts that failed this month. Ask for it at renewal, and record the answer.
Chrome and Firefox blocked eMudhra within hours of the report because someone owns their trust store. Name the owner of yours before the next CA incident.
Sources: CSO Online, 21 October 2026 ( https://www.csoonline.com/article/4238338/google-mozilla-revoke-emudhra-intermediates-after-private-key-compromise.html); Apple Support, “About the compromised eMudhra intermediate CAs” ( https://support.apple.com/en-us/149555); Veeam KB4952, 21 October 2026 ( https://www.veeam.com/kb4952); Red Sift, 21 October 2026 ( https://redsift.com/blog/emudhra-ca-key-compromise); Simon Willison, 20 October 2026 ( https://simonwillison.net/2026/Oct/20/emudhra-certificates); Help Net Security, 21–22 October 2026 ( https://www.helpnetsecurity.com/2026/10/21/php2shell-php-vulnerabilities-patched-cve-2026-109618-cve-2026-109619/); test hosts at https://emudhra.we-have-a-problem.com/ . The five-day sequence and ISO 27001 mapping are the author’s recommendation.