What happened, with dates
On 17 October 2026, a researcher reported to the root programs that eight eMudhra intermediate authorities had been created with badly generated keys. Firefox and Chrome blocked these certificates the same day. On 20 October 2026, Microsoft started blocking them and the curl bundle moved to its 20 October version. On 22 October 2026, Apple followed for applications that use its networking frameworks.
On 20 October 2026, Debian also published advisory DSA-6572-1: the ca-certificates package in version 20250419+deb13u1, for Debian stable (trixie), removes the certificates named "emSign ECC Root CA - G3" and "Comodo AAA Services root". Two details matter later. The advisory speaks of compromised eMudhra intermediates, but the two certificates it names carry root names. And it lists a fixed version only for trixie: for other distributions, read that distribution's own advisory rather than assuming.
Why "browsers already blocked it" does not close the case
This is the most common objection, and it is half right. According to the researcher's reference page, browsers that enforce Certificate Transparency could not be attacked through these intermediates. But a server calling an API, a deployment script cloning a repository, a scheduled job downloading an archive or a container installing a dependency are not browsers. These clients check the chain against a file, and generally check neither transparency nor revocation. On 28 October 2026, the researcher's reference page noted, for example, that Apple's command-line tools (git, curl, python3) still trusted these certificates.
Second objection: who is responsible? The agency owns the client relationship. The infrastructure is checked server by server, and nobody else will do it for you.
Where a trust store lives on a machine
- The system package —
ca-certificateson Debian, Ubuntu and Alpine, the same name on RHEL and derivatives. It is the reference for everything that reads/etc/ssl/certs. - The curl bundle — depending on the build, curl reads the system store or a separate file.
curl-config --catells you which. - Python and certifi — the
certifimodule ships its own bundle, and pip uses it. A system update does not touch it. - Node.js — the binary embeds a list of authorities.
NODE_EXTRA_CA_CERTSadds some, it removes none. - Java — the JDK
cacertsfile is a store independent of the rest. The OpenJDK fix was still pending on the reference page, and nothing guarantees that your distribution carries the system package update into it. - Every container image — it has its own
/etc/ssl/certs, frozen at build time. The host fix does not reach it.
Audit prerequisites, in numbers
Plan for root or sudo access on each machine, about 15 minutes for the first pass on a server, then 5 minutes as a routine once the commands are familiar. There are five places to inspect per machine (system package, curl, certifi, Node, Java) and one more per container image. Keep at least two test hosts whose chain you know, for example www.your-domain.com and an API your applications call. For Java services, also plan a restart window: a replaced store is only read again when the JVM starts.
The procedure, server by server
Read the package version
dpkg -l ca-certificateson Debian and Ubuntu,rpm -q ca-certificateson RHEL and derivatives,apk info -v ca-certificateson Alpine. On Debian stable (trixie), the fixed version in advisory DSA-6572-1 is 20250419+deb13u1: if yours is older, go to the next step.Update the store
On Debian and Ubuntu:
apt updatethenapt install --only-upgrade ca-certificates, thenupdate-ca-certificates. On RHEL and derivatives:dnf upgrade ca-certificatesthenupdate-ca-trust. On Alpine:apk upgrade ca-certificates.Check that the removed certificates are gone
ls /usr/share/ca-certificates/mozilla | grep -i -E 'emSign_ECC_Root_CA_-_G3|Comodo_AAA'ls /etc/ssl/certs | grep -i -E 'emSign_ECC_Root_CA_-_G3|Comodo_AAA'
After an update that removes the two certificates named by Debian, no line should come out. The pattern targets only the two certificates named by the Debian advisory, because other valid emSign or Comodo roots legitimately remain. A line means a store left at the old version, or a directory fed by hand. Check the real file names on an up-to-date machine.Test a chain from the server
openssl s_client -connect www.your-domain.com:443 -showcertsprints each certificate sent and ends with theVerify return codeline. Code 0 means the chain is accepted by the local store. Complete it withcurl -v https://www.your-domain.comand read theSSL certificate verify okline.List the bundles outside the system store
curl-config --cagives the path of the curl bundle.python3 -c "import certifi; print(certifi.where())"gives the Python one.echo $NODE_EXTRA_CA_CERTSshows any Node additions.readlink -f $(which java)leads back to the JDK, whoselib/security/cacertsis the store.Update certifi
pip show certifigives the installed version,python3 -m pip install --upgrade certifiupdates it. The researcher's reference page lists certifi 2026.10.19 among the fixed versions. Repeat in every virtual environment, since each has its own copy.Check the Java store
keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit | grep -i -E 'emsign ecc|aaa'looks for the entries concerned; aliases vary by JDK, so compare with the list on the reference page. The OpenJDK fix was still pending at the date of that page: if an affected entry is present, record the machine as "awaiting upstream" rather than "fixed".Record the result in your monthly audit
One line per server: date, ca-certificates version, bundle paths, chain test result. This record is what you show the client when they ask what was checked, and it fits into the monthly audit checklist for your client VPS.
Where to look, component by component
Scroll the table
| Component | Where the trust list lives | Check command |
|---|---|---|
| Debian, Ubuntu system | ca-certificates package, /etc/ssl/certs directory | `dpkg -l ca-certificates` |
| RHEL and derivatives system | ca-certificates package, store managed by update-ca-trust | `rpm -q ca-certificates` |
| curl | System store or build-time bundle | `curl-config --ca` |
| Python, pip | certifi module, independent of the system | `python3 -c "import certifi; print(certifi.where())"` |
| Node.js | List built into the binary, plus NODE_EXTRA_CA_CERTS | `echo $NODE_EXTRA_CA_CERTS` |
| Java | JDK cacerts file | `keytool -list -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit` |
| Docker container | /etc/ssl/certs specific to each image | `docker run --rm IMAGE ls /etc/ssl/certs` |
Containers: the host fix does not pass through
A container does not inherit its host's store. It carries the one from its base image, frozen on the day of the build. Updating ca-certificates on the server therefore changes nothing for your containers. To inspect an image, run docker run --rm IMAGE ls /etc/ssl/certs, or docker run --rm IMAGE dpkg -l ca-certificates if the image is based on Debian or Ubuntu.
The remedy is a rebuild: docker build --pull --no-cache -t my-application:2026-10 . pulls the latest base image and redoes the certificate layer. Without --pull, Docker reuses the cached base, and you rebuild the same defect. Then redeploy and rerun the check on the running container. Remember third-party images (database, proxy, monitoring tool) that you do not build: their publisher must release a new version, and you need to verify it.
If a client certificate chains to these authorities
There are two cases, and they must be kept apart. First: a certificate issued for your client, or for you, was signed by one of the affected intermediates. Read the issuer with openssl x509 -in certificat.pem -noout -subject -issuer -dates, then the served chain with openssl s_client -connect www.your-domain.com:443 -showcerts. The reference page publishes the list of affected intermediates (file impacted-intermediates.json): compare it with what you read. If the issuer is there, ask the issuing authority for a reissue under another chain, without waiting for expiry.
Second case: a partner connects to you with a client certificate (mTLS) and your server accepts it because its store contains an affected authority. After the update, that partner may be refused, which is the intended behaviour but must be announced. Warn them beforehand, list the active client certificates, and keep a record of the replacement date.
Test before and after, on real hosts
Removing a root can break legitimate chains attached to it. Before the update, run curl -sS -o /dev/null -w '%{http_code}\n' https://www.your-domain.com against three or four hosts that your applications really call, then rerun the same command afterwards. A changed code or a verification error is settled right away, on one server, rather than in production on a Monday morning.
Troubleshooting: the errors you will see
After the update, four messages come back. curl: (60) SSL certificate problem: unable to get local issuer certificate: the remote server sends an incomplete chain, or its chain went through a certificate that is now removed. Test with openssl s_client -showcerts, then ask the service owner to fix their chain.
ssl.SSLCertVerificationError: CERTIFICATE_VERIFY_FAILED on the Python side: the interpreter uses the certifi store or the system one, depending on the application. Read the path with certifi.where() and update the right component.
PKIX path building failed: unable to find valid certification path to requested target on the Java side: the cacerts file does not contain the expected authority or has been replaced. Check with keytool, then restart the JVM.
Verify return code: 20 (unable to get local issuer certificate) in openssl s_client: the authority is no longer in /etc/ssl/certs. If the site is legitimate, this is a signal to handle on the remote server, not to bypass by disabling verification.
What is still pending, and who carries what
At the date of the reference page, updated on 28 October 2026, the NSS library was fixed in version 3.131.1 and the curl bundle had been since 20 October 2026, but the OpenJDK fix was still pending, and Apple's command-line tools kept trusting the certificates. Reread that page before telling a client that everything is fixed: the state changes, and your report should state the date of the check.
For an agency, the split is simple. You keep the client relationship and the report that proves what was checked. The check itself happens machine by machine. If you run your own servers, the report is the same minus the client: one line per machine, with the date.