The eMudhra CA Compromise: Why Updating ca-certificates Isn't Enough
Browsers blocked the compromised eMudhra intermediates within hours. Your servers have more than one trust store — the OS bundle, the copies inside container images, and the list Node.js ships with. Where to look and what to change.
In October 2026 the private keys of eight eMudhra subordinate certificate authorities were found to have been generated with weak entropy, and the reporter demonstrated control of them. The intermediates chain to the emSign ECC Root CA - G3. According to Google, Chrome blocked them on 17 October with a CRLSet update, and removal of the root from the Chrome Root Store was expected to reach devices from 27 October. Google also stated that no TLS certificate chaining to these intermediates had been logged to Certificate Transparency before the block.
For browsers, the story ended quickly. For servers, it did not, because a server rarely has just one list of trusted roots.
Trust store 1: the operating system bundle
Ubuntu shipped ca-certificates updates that remove the emSign ECC Root CA - G3 (USN-8944-1). USN-8944-2 brings the same removal to older releases, where it also removes the Comodo AAA Services root. On 20.04 and older, that update is available through Ubuntu Pro (ESM).
dpkg-query -W -f='${Version}\n' ca-certificates
ls /etc/ssl/certs | grep -i emsign_ecc_root_ca_-_g3 || echo "not trusted"
On releases in standard support, unattended upgrades often install this for you. Check rather than assume. On a release without a fix, the manual equivalent is to mark the certificate as distrusted (prefix its line in /etc/ca-certificates.conf with !) and run update-ca-certificates.
Trust store 2: copies inside container images
Every container image carries its own CA bundle, frozen at build time. Updating the host does nothing for them. Copy the bundle out and read the actual subjects (don't grep for a guessed string):
docker cp <container>:/etc/ssl/certs/ca-certificates.crt ./bundle.pem
openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs -noout \
| grep -c "emSign ECC Root CA - G3"
The fix is a rebuilt image from an updated base. If that is not possible quickly, you can bind-mount the host's updated bundle into the container, but that means recreating the container, so plan the downtime.
Trust store 3: Node.js
Node.js does not use the operating system's bundle by default. It ships a compiled-in copy of the Mozilla root list. Updating ca-certificates on the host therefore changes nothing for a Node process. Check what your Node trusts:
node -e "const {X509Certificate}=require('crypto'); console.log(require('tls').rootCertificates.filter(c=>/emSign ECC Root CA - G3/.test(new X509Certificate(c).subject)).length)"
A result of 1 means the root is trusted. Node's October 2026 security releases (22.23.4, 24.22.1, 26.12.1) list a CA certificates update for the eMudhra compromise among their dependency updates, so upgrading Node is the direct fix. Until then, the --use-openssl-ca option (or the matching NODE_OPTIONS setting) makes Node use OpenSSL's store, which follows the updated system bundle. Note that NODE_EXTRA_CA_CERTS only adds certificates; it cannot remove a trusted root.
Trust store 4: everything else
Go programs embed their own handling as well. The Go team shipped a fix (CVE-2026-111943) that distrusts the compromised intermediates' keys. Java has its own cacerts, and Python's certifi package carries yet another copy. Any application that bundles its own list needs its own update.
And your own certificates?
Check who issued the certificates your sites serve. If none chain to the affected root, your visitors are unaffected:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -issuer
The lesson
"Update ca-certificates" fixes one trust store. List every place your systems decide whom to trust — OS, containers, language runtimes, bundled libraries — and check each one when a CA is distrusted.