# The eMudhra CA Keys Were One Byte Long. Does Your Container Still Trust Them?

> Eight eMudhra CA keys were one-byte numbers. Browsers blocked them in hours, but containers may not. A 15-minute trust store audit for Docker, Python, Java.

- URL: https://www.kielltampubolon.id/writing/the-emudhra-ca-keys-were-one-byte-long-does-your-container-still-trust-them/
- Author: Kiell Tampubolon
- Published: 2026-10-24
- Last updated: 2026-10-24
- Language: en
- Tags: Security Engineering, Deployment

## Key takeaways

- Eight eMudhra intermediate CA private keys were tiny numbers such as 4, 56 and 115, so recovering them meant trying 1, 2, 3 and so on.
- Chrome blocked the intermediates through CRLSet within hours, and Mozilla's OneCRL reached standard Firefox in under three hours.
- Per Endor Labs, default TLS stacks in Python, Go, Node and most CLI tools do not check revocation, so only a trust store update removes the risk.
- certifi 2026.10.19 and Alpine ca-certificates 20261020-r0 carry the change, while Java should be treated as unconfirmed until your JDK vendor says otherwise.
- Rebuild base images on a schedule, for example weekly in CI with docker build --pull --no-cache, so trust store versions are something you can query.

Eight private keys behind eMudhra intermediate CAs turned out to be single-byte numbers, guessable in milliseconds. Chrome and Firefox blocked them the same day. Your base image, your Python bundle and your JVM keystore blocked nothing until someone rebuilt them.

## TL;DR (for non-technical readers)

> - A certificate authority, one of the organizations that vouch for websites being genuine, created eight signing keys so weak that anyone could have worked them out.
> - Web browsers shut the door within hours. But servers, scripts, build systems and apps keep their own list of who to trust, and those lists do not update themselves.
> - The risk for a business is that an attacker could impersonate a trusted service to your software, not to your customers' browsers.
> - Ask your tech team: "Where do our services get their list of trusted certificate authorities, and when was it last refreshed?"

## What happened

The facts, from [eMudhra's statement](https://emudhra.com/en/post/certificate-security-incident), [Scott Helme's analysis](https://scotthelme.co.uk/eight-bits-of-trust-emudhras-ca-keys-cracked-in-milliseconds/) and the [dev.to summary](https://dev.to/jamilxt/after-the-emudhra-ca-incident-update-more-than-your-browser-3m52):

![Comparison of expected random 384-bit CA keys versus the tiny numbers 4, 56 and 115 that were actually found, so the search is just 1, 2, 3 and so on.](https://www.kielltampubolon.id/writing/the-emudhra-ca-keys-were-one-byte-long-does-your-container-still-trust-them/img-1.png)

- A researcher reported on October 17, 2026 that private keys of eight eMudhra intermediate CAs were compromised.
- Helme found the keys were not random 384-bit values. They were tiny numbers such as 4, 56 and 115, so the "search" is trying 1, 2, 3 and so on. Google's wording is that the keys were generated with insufficient randomness. That is technically true and a big understatement.
- eMudhra says a flaw in the key wrap/unwrap step of a ceremony on April 30, 2025 produced a second, weak key set next to the strong one, and the weak set was what got published to root programs.
- eMudhra also says root keys were not affected, and that none of the eight intermediates issued a certificate for a real site. One was in production but had issued nothing.
- Chrome blocked the intermediates through CRLSet within hours. Mozilla's OneCRL reached standard Firefox in under three hours.
- According to [Google's security blog](https://blog.google/security/protecting-chrome-and-android-users-from-compromised-emudhra-intermediate-ca-certificates/), the emSign ECC Root CA - G3 is also being removed from the Chrome Root Store, rolling out October 27, 2026.

## The gap


![Trust store map: browsers block compromised CAs in hours, while Debian/Ubuntu images, Python certifi, Java cacerts and vendored stores stay stale until rebuilt, upgraded or released.](https://www.kielltampubolon.id/writing/the-emudhra-ca-keys-were-one-byte-long-does-your-container-still-trust-them/img-2.png)
```plaintext
Browser            -> fast distrust lane (CRLSet, OneCRL)   -> blocked in hours
Debian/Ubuntu img  -> ca-certificates package, baked in      -> stale until rebuilt
Python (certifi)   -> its own bundle                         -> stale until upgraded
Java (cacerts)     -> JDK keystore                           -> wait for JDK vendor
Vendored (Go, Node, mobile, firmware) -> frozen snapshots    -> depends on release
```

Per [Endor Labs](https://www.endorlabs.com/learn/emudhra-intermediate-ca-compromise-the-trust-stores-you-patched-and-the-ones-you-didnt-know-you-had), certifi 2026.10.19 and Alpine ca-certificates 20261020-r0 carry the change, and Java should be treated as unconfirmed until your JDK vendor says otherwise. Their key point: default TLS stacks in Python, Go, Node and most CLI tools do not check revocation, so only a trust store update removes the risk.

## What practitioners are saying

- **Process failure.** On [LWN](https://lwn.net/Articles/1101643/), one commenter asked how an HSM could ever produce a one-byte key, suspecting the problem runs deeper than one buggy script.
- **Marketing versus reality.** Another noted the CA advertised post-quantum and zero-trust language while shipping what amounted to one byte of entropy.
- **Storage doubts.** A third pointed out that eMudhra's trouble verifying its own CRL signatures suggests keys were not held in HSMs the way they should be.
- **A structural fix.** One commenter proposed requiring HSM attestation for every root and intermediate, so key generation can be proven.
- **The "it was contained" view.** Not everyone saw an emergency. Because no certificate chaining to the six TLS intermediates had been logged in Certificate Transparency, browsers that require CT would not have accepted a forged one anyway. Helme's counterpoint is that curl and Python happily accepted a forged chain in his proof of concept.

## My take

I side with the people who say the CA is the story and the people who say the trust store is the lesson, and I think both are right at different layers.

The browser response was excellent and I do not want to undersell it. Hours, not weeks. But that speed only protects the one client type built for it. The honest framing is that the web PKI has a fast lane for browsers and a slow lane for everything else, and most backend traffic is in the slow lane.

Where I disagree with the "contained" view: no certificate being logged is not a guarantee about the future. The keys are public, so the only thing standing between your internal client and a forged cert is whether your trust store still lists the parent. That is something you can fix with a rebuild, so do it.

For teams, this argues for one boring policy: base images are rebuilt on a schedule, and trust store versions are something you can query, not something you hope about. It also supports CA diversity and short certificate lifetimes, because swapping a CA is much easier when you have practiced it.

## Try it in 15 minutes

### 1. List what makes outbound TLS calls

![Five-step 15-minute trust store audit: list TLS callers, check OS bundle, check language bundles, inspect server certificates, rebuild images weekly.](https://www.kielltampubolon.id/writing/the-emudhra-ca-keys-were-one-byte-long-does-your-container-still-trust-them/img-3.png)

Services, workers, CI runners, scripts. Ask "which trust store", not "which version".

### 2. Check the OS bundle in a running container

```bash
docker exec <container> sh -c 'ls -l /etc/ssl/certs/ca-certificates.crt; grep -c "BEGIN CERTIFICATE" /etc/ssl/certs/ca-certificates.crt'
docker exec <container> dpkg -l ca-certificates
docker exec <container> sh -c 'ls /etc/ssl/certs | grep -i emsign'
```

Compare the `ca-certificates` version with what your distro ships now (Endor lists Debian and Ubuntu fixed versions). A file date older than October 17 on a long-lived image means rebuild.

### 3. Check language bundles

```bash
python -c "import certifi; print(certifi.__version__, certifi.where())"
pip install --upgrade certifi
keytool -list -cacerts -storepass changeit | grep -i emsign
```

`requests` uses certifi unless you override `verify=`, so one machine can hold two different truths. For Java, `changeit` is the default cacerts password. The fix is a newer JDK build, not hand-editing the keystore.

### 4. See what a server presents

```bash
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
openssl x509 -in certificate.pem -noout -issuer -subject -fingerprint -sha256
```

If an issuer names an eMudhra or emSign intermediate, find out why and when it renews.

### Make it stick

```bash
docker build --pull --no-cache -t myapp:$(date +%Y%m%d) .
```

Run that weekly in CI. Fresh base images carry fresh trust stores.

## What to learn next

- [eMudhra's own incident statement](https://emudhra.com/en/post/certificate-security-incident), for the cause as the CA tells it.
- [Scott Helme's write-up](https://scotthelme.co.uk/eight-bits-of-trust-emudhras-ca-keys-cracked-in-milliseconds/), for how the keys were recovered and what non-browser clients accepted.
- The [Chrome Root Program policy](https://www.chromium.org/Home/chromium-security/root-ca-policy/), to see why a root can be pulled on a date.

## Question

If a CA you depend on were distrusted tomorrow, could you say in under ten minutes which of your services would still trust it?

*Originally published on [DEV](https://dev.to/kielltampubolon/the-emudhra-ca-keys-were-one-byte-long-does-your-container-still-trust-them-1c5). Discussion happens there.*

## FAQ

### How do I check if my container still trusts the eMudhra CA?

Run docker exec <container> sh -c 'ls /etc/ssl/certs | grep -i emsign' and check the ca-certificates version with dpkg -l ca-certificates. A file date older than October 17 on a long-lived image means rebuild.

### Why do curl and Python still trust compromised CAs after browsers block them?

Browsers have a fast distrust lane (CRLSet, OneCRL), but Python, Go, Node and most CLI tools do not check revocation. Their trust stores only change when you update or rebuild.

### How do I update the Python and Java trust stores?

For Python, run pip install --upgrade certifi. For Java, the fix is a newer JDK build, not hand-editing the keystore.

### Were eMudhra's root keys affected?

eMudhra says root keys were not affected, and that none of the eight intermediates issued a certificate for a real site. One was in production but had issued nothing.
