Java now has a fix for the eMudhra key compromise. On 21 October 2026 Azul, Oracle and the OpenJDK project shipped builds that add all sixteen affected certificates to the JDK block list, and Azul published a workaround for existing Zulu installs. Update every standalone JVM, or replace its blocked.certs file, restart it, then prove the block works.
Two days ago we wrote that Java had no confirmed eMudhra fix. That was true when we checked, and it stopped being true within hours. This post covers what has shipped since our 21 October guide to checking and fixing Java trust stores, vendor by vendor, with exact versions, file hashes and the commands to confirm that a running JVM really picked up the change. For the incident itself, start with our eMudhra CA key compromise explainer.
Key takeaways
- The fix is a block list, not a root removal. Oracle and OpenJDK add the eight eMudhra intermediates and their eight Sectigo cross-signs to
lib/security/blocked.certs(blacklisted.certson JDK 8). The emSign and AAA Certificate Services roots stay incacerts. - Azul moved first among third-party vendors. On 21 October Azul published out-of-cycle Zulu builds for versions 27, 25, 21, 17, 11, 8, 7 and 6, plus a file-replacement workaround with published SHA-256 values.
- Oracle shipped a Security Alert. CVE-2026-91403, CVSS 3.1 base score 9.1, with JDK 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2 and 8u511 b32, all dated 21 October.
- Upstream OpenJDK has the change and an advisory. The change is tracked as JDK-8395142, "CA Enhancements"; release tags for 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2 and 17.0.21.0.2 exist in the OpenJDK update repositories.
- Other vendors were silent when we checked on 23 October. We found no eMudhra statement from Eclipse Temurin, Amazon Corretto or Microsoft Build of OpenJDK. Red Hat's bulletin is still open.
- Verification beats version numbers. Check the version string, check the block list file, check the JVM restarted after the change, then run a TLS test against the tracker's hosts.
What changed since 21 October
Our earlier post listed the community tracker's Java entry as "Pending" and found no statements from Oracle, Eclipse Temurin, Amazon Corretto or Azul. By 23 October the tracker's Java row lists fixed versions 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2 and 8u511, labelled for OpenJDK and Oracle JDK.
Frank Delporte of Azul's documentation team flagged Azul's fix to us after our 21 October post. Foojay.io, the Friends of OpenJDK community site, has since published a walkthrough of the Azul Zulu October 2026 quarterly update and the out-of-cycle release that covers both releases together and lists our 21 October guide among its references.
Several releases are dated 21 October, the day our post went live. Times below are UTC where the source gives a time zone.
| When | What happened | Source |
|---|---|---|
| 17 Oct, 20:06 UTC | Mozilla receives the report that keys for eight eMudhra intermediates are compromised | Mozilla Security Blog |
| 17 Oct, 22:59 UTC | OneCRL update reaches all Firefox users with standard settings | Mozilla Security Blog |
| 19 Oct | Issue disclosed to downstream trust stores | Community tracker |
| 20 Oct | Mozilla publishes its blog post; the tracker page is dated the same day | Mozilla, tracker |
| 20 Oct | Oracle's October 2026 Critical Patch Update, Rev 1, with 55 Java SE patches and no eMudhra entry | Oracle CPU advisory |
| 20 Oct, 21:35 UTC | JDK-8395142 "CA Enhancements" authored in the OpenJDK mainline repository | OpenJDK GitHub |
| 21 Oct | Oracle Security Alert for CVE-2026-91403, Rev 1; Oracle JDK 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2 and 8u511 b32 released | Oracle |
| 21 Oct | OpenJDK Vulnerability Advisory 2026/10/21 lists CVE-2026-91403 for JDK 8, 11, 17, 21, 25 and 27 | OpenJDK |
| 21 Oct | Azul out-of-cycle Zulu release notes, revision 1.3, and the eMudhra workaround page | Azul |
| 21 Oct, 17:06 UTC | JDK-8395142 committed to OpenJDK mainline | OpenJDK GitHub |
| 21 Oct, 19:25 UTC | JDK-8395142 lands in the jdk27u repository | OpenJDK GitHub |
| 22 Oct, 15:17 UTC | JDK-8395142 lands in jdk25u, jdk21u and jdk17u, after version bumps to 25.0.5.0.2, 21.0.13.0.2 and 17.0.21.0.2 | OpenJDK GitHub |
| 22 Oct, 19:08 UTC | JDK-8395142 lands in jdk11u | OpenJDK GitHub |
| 22 Oct, 19:40 UTC | JDK-8395142 lands in jdk8u | OpenJDK GitHub |
| 22 Oct | Tracker adds two "No CT" test chains whose leaf certificates were never logged to Certificate Transparency | Community tracker |
| 23 Oct, 02:10 | Red Hat updates RHSB-2026-012; status still "Ongoing" | Red Hat |
| 23 Oct, 05:42 to 05:59 UTC | Amazon Corretto October releases appear on GitHub; changelogs do not mention eMudhra | Corretto GitHub |
The tracker now says Microsoft platforms have blocked the certificates since 20 October and Apple products since 22 October. Neither reaches a JVM, which carries its own trust.
Azul: out-of-cycle Zulu builds and a workaround
Azul's release notes describe this as an update release for the October 2026 quarterly update of Azul Zulu Builds of OpenJDK versions 27, 25, 21, 17, 11, 8, 7 and 6. Azul recommends updating "ASAP" and offers the workaround for runtimes that cannot be updated at once.
Azul's reason matches what we described on 21 October: Zulu trusts the roots these intermediates chain to and does not check revocation by default.
The builds
Community Availability (CA) builds are free; Subscriber Availability (SA) builds are commercially supported. CPU builds carry only security fixes, PSU builds add non-security fixes. Azul lists:
| Zulu version | Update type | JDK version | JavaFX version |
|---|---|---|---|
| 27.30.107 (CA), 27.30.108 (SA) | PSU | 27.0.1+9 | 27.0.1+101 |
| 25.38.107 (CA), 25.38.108 (SA) | PSU | 25.0.5+8 | 25.0.5+100 |
| 25.37.114 (SA) | CPU | 25.0.4.1.101+1 | 25.0.4.0.101+102 |
| 21.54.107 (CA), 21.54.108 (SA) | PSU | 21.0.13+9 | 23.0.9+102 |
| 21.53.112 (SA) | CPU | 21.0.12.1.101+1 | 23.0.8.0.101+101 |
| 17.70.111 (CA), 17.70.112 (SA) | PSU | 17.0.21+9 | 22.0.11+103 |
| 17.69.112 (SA) | CPU | 17.0.20.1.101+1 | 22.0.10.0.101+101 |
| 11.92.109 (CA), 11.92.110 (SA) | PSU | 11.0.33+9 | 19.0.17+102 |
| 11.91.112 (SA) | CPU | 11.0.32.1.101+1 | 19.0.16.0.101+101 |
| 8.98.0.107 (CA), 8.98.0.108 (SA) | PSU | 8u512-b08 | 8u512-b02 |
| 8.97.0.110 (SA) | CPU | 8u511-b01 | 8u511-b03 |
| 7.89.0.110 (SA) | CPU | 7u521-b01 | N/A |
| 6.83.0.108 (SA) | CPU | 6b191 | N/A |
One detail catches people out: each PSU respin keeps the JDK version of the regular October build it is based on (Zulu 21.54 reports JDK 21.0.13+9 either way). The Zulu version tells you whether you have the respin, not the JDK version string.
Azul's fixed-issues table lists one change, JDK-8395142 "CA Enhancements", in versions 6, 7, 8, 11, 17, 21, 25 and 27, in both CPU and PSU bundles. That is the same change ID as the upstream OpenJDK commit.
Azul says the release adds the compromised intermediates to lib/security/blocked.certs (blacklisted.certs before JDK 11) and that no manual workaround is needed after upgrading. Since browsers and operating systems already block these certificates, Azul expects no impact on legitimate connections.
The workaround, in short
For Zulu runtimes that cannot move to a new build yet, Azul's workaround replaces the block list file in place. In our words, the steps are:
- Download the right file. One file for Linux, macOS and containers, one for Windows. Check its SHA-256 against the value Azul publishes and do not use a file whose checksum does not match.
- Do not open it in a text editor. Azul warns that some editors add an invisible marker that makes Java ignore the whole list.
- Find the file to replace in the installation's
lib/securitydirectory. Azul lists default paths for its APT, DEB, RPM, macOS and Windows MSI installs, and says to addjre/beforelib/securityon a Zulu 8 JDK. For anything else, run that installation'sjava -XshowSettings:properties -versionand use thejava.homevalue. If the directory has neitherblocked.certsnorblacklisted.certs, Azul asks you to contact its support. - Back up, then copy. Keep the original as a
.bak-emudhracopy and copy the new file over it. Azul says to copy rather than move, because a moved file can keep permissions Java cannot read. On Windows, copy and paste rather than drag. - Restart every Java application that uses the installation, including Windows services such as application servers.
- Verify the installed file's SHA-256 and confirm the applications restarted after the change.
Azul also publishes shell and PowerShell scripts that do this for one installation, checking the runtime is Zulu, verifying the checksum and restoring the backup if the copy fails, plus a command that lists every Zulu installation on a machine.
These are the published values:
| File | Platform | SHA-256 (as published by Azul) |
|---|---|---|
emudhra-block-unix.certs | Linux, macOS, containers | 2596bb6dda83c66d96c5a252d7b2ae1f24cc1ae3f1890223b4f3591a8d52bf10 |
emudhra-block-windows.certs | Windows | 101200f8ff64a4375a03601cf0200d0f9fec449d1a173aaf1459a5765ae7e5ae |
We downloaded both files on 23 October and their SHA-256 values matched these. The Unix file is plain text: an Algorithm=SHA-256 line followed by 86 fingerprints, one per line. All sixteen eMudhra fingerprints from our 21 October list are in it. The Windows file has the same content with Windows line endings, which is why its hash differs.
Azul's page also covers cases the basic steps miss:
- Containers: patch the image or the deployment, not a running container. Azul shows how to find the file's path in an image, then either rebuild with a
COPYof the new file or mount it as a single read-only file, for example from a Kubernetes ConfigMap. Windows containers cannot mount single files, so rebuild those. - CI jobs that download Zulu, such as a setup-java step, should run the script right after the JDK is set up.
- jlink runtimes: copy the file into the runtime's
lib/securityafter every build. Azul notes that patching the JDK does not help here, because jlink takes the file from the jmods. - Applications that bundle Java, such as jpackage builds: update the bundled runtime in your own builds and re-sign on macOS. For vendor applications, ask the vendor.
- CRaC: create new checkpoints after the change, because existing checkpoints keep the old list.
Once you upgrade, Azul says to remove the backups, COPY lines, mounts and CI steps, since they would hide future list updates. A Zulu update without the fix restores the original file, so reapply the workaround after one.
JDK vendor status as of 23 October 2026
We checked each vendor's own official pages only: release notes, security advisories, changelogs and release listings. "No statement found" means we found nothing on those pages on 23 October 2026, not that the vendor has done nothing.
| Vendor | Status on 23 Oct 2026 | Versions or detail | Where we looked |
|---|---|---|---|
| Azul Zulu | Out-of-cycle builds and workaround published 21 Oct 2026 | Zulu 27.30.107/108, 25.38.107/108, 25.37.114, 21.54.107/108, 21.53.112, 17.70.111/112, 17.69.112, 11.92.109/110, 11.91.112, 8.98.0.107/108, 8.97.0.110, 7.89.0.110, 6.83.0.108 | Azul release notes and workaround page |
| Oracle JDK | Fixed builds and Security Alert published 21 Oct 2026 | 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2, 8u511 b32 (full version strings end in +1, or -b32 for 8) | Oracle release notes for each line; Security Alert CVE-2026-91403 |
| Oracle October CPU | No eMudhra entry | CPU Rev 1 dated 20 Oct; 55 Java SE patches; eMudhra handled by the separate Security Alert | Oracle CPU advisory, October 2026 |
| OpenJDK (upstream) | Change committed and advisory published | JDK-8395142 in mainline and in jdk27u, jdk25u, jdk21u, jdk17u, jdk11u and jdk8u; -ga tags exist for 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2 and 17.0.21.0.2; no 11u or 8u release tag with the change found | OpenJDK Vulnerability Advisory 2026/10/21; OpenJDK GitHub repositories |
| Eclipse Temurin (Adoptium) | No statement found on 23 Oct 2026 | Latest GA releases listed: jdk-25.0.5+8, jdk-21.0.13+9, jdk-17.0.21+9; no 0.2 builds listed | adoptium.net news and release notes; Adoptium API; Temurin GitHub releases |
| Amazon Corretto | No statement found on 23 Oct 2026 | October releases 25.0.5.0.9, 21.0.13.0.10, 17.0.21.0.10, 11.0.33.0.9 and 8.512.08.1 published on GitHub 23 Oct; the 25, 21 and 17 changelog entries (release date 20 Oct) do not mention eMudhra or JDK-8395142 | Corretto GitHub releases and changelogs; AWS security bulletins |
| Microsoft Build of OpenJDK | No statement found on 23 Oct 2026 | Release notes page listed no October 2026 release | Microsoft Learn release notes and download page; Microsoft Java blog feed |
| Red Hat build of OpenJDK | Analysis published; no fixed build listed | Non-portable RHEL OpenJDK RPMs take their trust from ca-certificates (tracked as CVE-2026-114406); portable builds carry their own store and will be updated separately | Red Hat CVE-2026-91403 page; RHSB-2026-012 |
A few notes on reading that table.
Temurin. In the upstream jdk25u, jdk21u and jdk17u repositories, the eMudhra commit sits after the version bump to the 0.2 releases, so do not assume a jdk-25.0.5+8, jdk-21.0.13+9 or jdk-17.0.21+9 build contains the block. Check its blocked.certs file with step 3 below.
Corretto. A changelog that does not mention a change proves nothing either way. Check the file.
Red Hat. For RHEL's own OpenJDK RPMs, the system ca-certificates update is what matters, and RHSB-2026-012 still listed no fixed errata at its 23 October 02:10 update. Its interim mitigation is to blocklist the two roots involved, following Red Hat knowledge base articles.
Distribution packages. The OpenJDK advisory says the OpenJDK packages in Arch Linux, Debian, Devuan, Fedora, Gentoo, Oracle Linux, Red Hat Enterprise Linux and Ubuntu most likely use the operating system's certificates, so updating those is sufficient there. It says this is not true for FreeBSD and Homebrew packages, which must be updated directly.
Technical details
The identifiers
| Item | Value | Source |
|---|---|---|
| CVE for Java | CVE-2026-91403 | Oracle Security Alert; OpenJDK advisory; Red Hat |
| CVSS 3.1 (Oracle and OpenJDK) | 9.1; vector AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N; component JSSE (Oracle), security-libs/javax.net.ssl (OpenJDK) | Oracle; OpenJDK; cve.org vector as shown by Red Hat |
| Red Hat's own vector | AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N, marked preliminary | Red Hat CVE page |
| OpenJDK change | JDK-8395142 "CA Enhancements" | OpenJDK GitHub; Azul release notes |
| Oracle release note IDs | JDK-8395555 (11 and later lines), JDK-8395593 (8u511 b32), both "not public" | Oracle release notes |
| Red Hat Bugzilla | 2558584, "OpenJDK: Distrust eMudhra intermediate CA certificates due to security concerns" | Red Hat CVE page |
RHEL ca-certificates CVE | CVE-2026-114406 | RHSB-2026-012 |
| Other ecosystem CVEs named by Red Hat | CVE-2026-111943 (Go), CVE-2026-113812 (Perl Mozilla::CA) | RHSB-2026-012 |
| Mainline commit | 22bc7357ce6bc5f1ed2f1e83e0544b2c25f781d4, authored 2026-10-20T21:35:46Z, committed 2026-10-21T17:06:26Z | OpenJDK GitHub |
| Files changed upstream | blocked.certs.pem (+430 lines), BlockedCertsConverter.java, CheckBlockedCerts.java test | OpenJDK GitHub |
The OpenJDK advisory gives affected versions as 27.0.1, 25.0.5, 21.0.13, 17.0.21, 11.0.32.1, 8u504 and earlier. Oracle's alert lists Oracle Java SE 8u511, 8u511-perf, 11.0.33, 17.0.21, 21.0.13, 25.0.5 and 27.0.1, Oracle GraalVM for JDK 17.0.21 and 21.0.13, and Oracle GraalVM Enterprise Edition 21.3.20. Use your own vendor's list.
The sixteen certificates now in the JDK block list
These are the certificates added to OpenJDK's blocked.certs.pem on the mainline branch. We parsed each one and computed its SHA-256 fingerprint; all sixteen match the fingerprints in our 21 October post and the entries in Azul's block list file. All sixteen use EC public keys.
| Subject CN | Issuer CN | Serial (hex) | SHA-256 fingerprint | Not after |
|---|---|---|---|---|
| EM DV TLS CA - G3B | emSign Root TLS CA - G3 | A4AEE678F23362B4C0E460B772F214 | 42C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA1493 | 28 Apr 2040 |
| EM DV TLS CA - G3C | emSign Root TLS CA - G3 | 588B2E3C2BB8CDA13E1A1209254321 | 0164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D19 | 28 Apr 2040 |
| EM EV TLS CA - G3B | emSign Root TLS CA - G3 | C7C41EFE92D825F05EAE841A4A82C1 | E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA75184333838 | 28 Apr 2040 |
| EM EV TLS CA - G3C | emSign Root TLS CA - G3 | 8009928A64107601AF05FA2F19F109 | 432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F3 | 28 Apr 2040 |
| EM OV TLS CA - G3B | emSign Root TLS CA - G3 | 6CADA367FB1C100088120EA202D568 | 98B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B | 28 Apr 2040 |
| EM OV TLS CA - G3C | emSign Root TLS CA - G3 | 296926C227A3A1526392B19482A504 | CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F | 28 Apr 2040 |
| EM OV CS CA - G3B | emSign Root CS CA - G3 | 7818933F8F85B4619A2B35FBA83D0A | 9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B4 | 28 Apr 2040 |
| EM OV CS CA - G3C | emSign Root CS CA - G3 | 544B7F922C31AE220A4A922916F6E6 | 4B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B1 | 28 Apr 2040 |
| EM DV TLS CA - G3B | AAA Certificate Services | A024FDF4BA665C785CE4A020483858B7 | 45A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE | 31 Dec 2028 |
| EM DV TLS CA - G3C | AAA Certificate Services | 91F347F1A5B7D39962B95E0EE4E299D1 | 62B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E72 | 31 Dec 2028 |
| EM EV TLS CA - G3B | AAA Certificate Services | D8F8685E4F2BD9D82402A85A1C1EB731 | 579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD3199512 | 31 Dec 2028 |
| EM EV TLS CA - G3C | AAA Certificate Services | 05F078752DECE7A1BB8595D303167171 | FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F | 31 Dec 2028 |
| EM OV TLS CA - G3B | AAA Certificate Services | E94223BDE92F914E5AB9ACABFDAC3710 | 5F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD832699 | 31 Dec 2028 |
| EM OV TLS CA - G3C | AAA Certificate Services | 8D5A4811939EF447D77111CDD9849AE9 | 7485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE9489 | 31 Dec 2028 |
| EM OV CS CA - G3B | AAA Certificate Services | 41E32B73AC185D6CE0D7480BACF84E69 | A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D8 | 31 Dec 2028 |
| EM OV CS CA - G3C | AAA Certificate Services | D6A5EF613B390F32EF9CDF349F772841 | 84112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD | 31 Dec 2028 |
The G3B subjects carry the organisation eMudhra BV (Netherlands) and the G3C subjects eMudhra Inc (United States), according to the comment headers in the upstream file. The CS intermediates are the two code signing CAs; the rest are TLS.
What Oracle says the block does
Oracle's release notes for each fixed line describe the effect in two sentences that matter for operations. For TLS, a session will not be negotiated if the server's certificate chain contains one of the compromised certificates. For signed code, jarsigner -verify -strict fails for a JAR signed with a chain containing one of them. Oracle's notes say the change covers "8 eMudhra intermediate CA certificates and 8 certificates cross-signed by Sectigo."
Why a block list works when the roots stay trusted
On 21 October we explained that a Java keystore has no way to say "this intermediate is bad," which left two blunt tools: delete roots, or turn on revocation checking. The vendor fix uses a third tool outside the keystore.
The JDK keeps a separate file of certificates it will never accept, lib/security/blocked.certs (blacklisted.certs on JDK 8). The file is plain text: an algorithm line and a list of certificate fingerprints. When the JDK checks a certificate chain, any certificate in that chain whose fingerprint is on the list causes the check to fail, whichever root the chain ends at. That is what Oracle's release note means when it says a TLS session will not be negotiated if the chain "contains" one of the certificates.
So the trust anchors can stay exactly where they are:
emsigneccrootcag3stays incacerts, but any chain that passes through one of the eight eMudhra-issued intermediates fails because the intermediate is on the list.comodoaaaca(AAA Certificate Services) stays incacerts, but any chain that passes through one of the eight Sectigo cross-signs fails for the same reason.- Every other chain under those roots keeps working. That is the big advantage over our 21 October fallback of deleting
comodoaaaca, which could break older Sectigo chains you still depend on.
Red Hat's CVE page describes the same design: the upstream fix "does not remove this root certificate" but blocks the intermediates. Three consequences follow.
It matches certificates, not keys. The list names the exact sixteen certificates by fingerprint. If another certificate for the same keys turned up, the list would need a new entry. Today both trust paths are covered, which is why the count is sixteen and not eight.
It is read from disk, so the JVM must restart. Azul's instructions require restarting every Java application after replacing the file, and say CRaC checkpoints keep the old list. Treat a running JVM as holding whatever list it had when it started.
One bad byte can disable it. Azul warns that some text editors add an invisible marker that makes Java ignore the whole list. A broken block list fails quietly: connections succeed, which is the one result you do not want.
Revocation checking is still a valid extra layer. The OpenJDK advisory lists it as the second option for runtimes that cannot be updated: -Dcom.sun.net.ssl.checkRevocation=true -Dcom.sun.security.enableCRLDP=true for TLS, and jarsigner -verify -revcheck -strict for signed JARs on JDK 17 and later. Our earlier post covers its costs, mainly network fetches during handshakes.
Step by step: check every JVM
These steps use only commands documented by Oracle, OpenJDK, Azul or the tracker, plus standard shell tools. Run them per installation and per image, not per host.
1. List every Java installation
Azul's appendix finds Zulu installations by their release file. For a vendor-neutral list, find every block list file, then read the release file next to it:
# Every JDK or JRE block list on the host (skip container storage; check images separately)
sudo find / -xdev -path '*/lib/security/*' \( -name blocked.certs -o -name blacklisted.certs \) 2>/dev/null \
| while read -r f; do
h=${f%/lib/security/*}
vendor=$(grep -hsE '^(IMPLEMENTOR|JAVA_VERSION)=' "$h/release" "$h/../release" | tr '\n' ' ')
echo "$f $vendor"
done
On a Zulu 8 JDK the file lives under jre/lib/security, which the pattern above still matches.
2. Read each runtime's version and home
JAVA_BIN=/path/to/bin/java
"$JAVA_BIN" -version
"$JAVA_BIN" -XshowSettings:properties -version 2>&1 | grep -E 'java\.(home|vendor|runtime\.version) '
Compare the output with the vendor table above. For Oracle JDK, a fixed runtime reports a full version string such as 25.0.5.0.2+1, 21.0.13.0.2+1, 17.0.21.0.2+1, 11.0.33.0.2+1 or 1.8.0_511-b32, per Oracle's release notes. For Zulu, the Zulu version shown in the runtime name is what to compare, since the PSU respins keep the JDK version of the build they are based on.
3. Check the block list itself
This is the check that does not depend on any vendor's version scheme. Save the sixteen fingerprints from the Technical details table into emudhra-bad.txt, one per line, uppercase, no colons (the same list as in our 21 October post), then count how many appear in each runtime's block list:
SEC="$("$JAVA_BIN" -XshowSettings:properties -version 2>&1 | sed -n 's/^ *java\.home = //p')/lib/security"
F="$SEC/blocked.certs"; [ -f "$F" ] || F="$SEC/blacklisted.certs"
grep -c -F -f emudhra-bad.txt "$F" # 16 means all present; 0 means unfixed
head -1 "$F" # expect: Algorithm=SHA-256
If you applied Azul's workaround, also compare the file hash with Azul's published value:
sha256sum "$F" # Linux
shasum -a 256 "$F" # macOS
certutil -hashfile "C:\Program Files\Zulu\zulu-17\lib\security\blocked.certs" SHA256
A vendor's own fixed build will have a different hash from Azul's workaround file, because each vendor's list may hold different older entries. Use the fingerprint count for those, and the hash only for Azul's file.
4. Confirm the JVM restarted after the change
A correct file does nothing for a process that started before it was written. Compare the process start time with the file's modification time:
stat -c '%y %n' "$F" # Linux (macOS: stat -f '%Sm %N' "$F")
for pid in $(jcmd -l | awk '$2 !~ /JCmd/ {print $1}'); do
printf '%s started: ' "$pid"; ps -o lstart= -p "$pid"
jcmd "$pid" VM.system_properties 2>/dev/null | grep -E '^java\.home='
done
Any JVM whose java.home matches a patched runtime and whose start time is earlier than the file change still holds the old list. Restart it.
5. Test the real TLS behaviour
The tracker serves chains through each trust path. Use the TlsCheck.java program from our 21 October post, run with the same JDK and the same trust settings as your service:
for h in dv-g3b-emudhra dv-g3b-aaa-emudhra dv-g3b-noct-emudhra dv-g3b-aaa-noct-emudhra; do
echo "== $h"; "$JAVA_BIN" TlsCheck.java "https://$h.we-have-a-problem.com/" 2>&1 | grep -m1 -E 'ACCEPTED|Exception'
done
You want a handshake failure from every host. The two "noct" hosts were added on 22 October; the tracker explains their leaf certificates were never logged to Certificate Transparency, so clients that enforce CT reject them anyway. A default JVM does not enforce CT, so for Java all four should fail only because of the block list. If any line prints ACCEPTED (bad), that runtime still trusts the chain.
6. Check container images, not containers
Azul's documented approach works for any vendor's image. Find the file path inside the image, then hash or count it without running the image:
id=$(docker create your-java-app:latest x)
docker export "$id" | tar -tvf - | grep -E 'lib/security/(blocked|blacklisted)\.certs'
docker cp -L "$id:/opt/java/openjdk/lib/security/blocked.certs" - | tar -xOf - \
| grep -c -F -f emudhra-bad.txt
docker rm -v "$id"
Replace the path with the one from the listing. If the count is not 16, rebuild on a fixed base, or for Zulu images apply Azul's COPY or mount approach until a fixed base exists.
7. Check distribution-managed Java
For Debian and Ubuntu OpenJDK packages, the OpenJDK advisory says updating the operating system's certificates is sufficient. The tracker adds that the Java certificate store can fall out of sync with the system store, and gives this resync, run as root:
touch /var/lib/ca-certificates-java/fresh
dpkg-reconfigure ca-certificates-java
For RHEL's OpenJDK RPMs, Red Hat says they consume the ca-certificates fix. Check the installed version with rpm -q ca-certificates and watch RHSB-2026-012 for errata. Until errata ship, Red Hat's mitigation is its knowledge base procedure for blocklisting the two roots.
Where the 21 October advice still applies
The main fix is now "update or replace the block list," not "remove anchors." Some of our earlier advice still stands:
- Custom trust stores set with
javax.net.ssl.trustStore, andjssecacertsfiles, are separate fromcacerts. The block list applies to chain validation whichever trust store is used, so an updated runtime should reject the chains here too. Test with the trust settings your service actually uses, as in step 5. - Android apps that bundle their own CA files are outside the JDK fix entirely. The device block from Google Play Services covers the system store, not an app's inline anchors.
- If you deleted
comodoaaacaon 21 October, you can leave it deleted, or restore it once the runtime has the block list and you have confirmed nothing you need chains through it. Make the decision on purpose and write it down.
Common mistakes
- Trusting the JDK version string on Zulu. The PSU respins keep the JDK version of the build they are based on. Check the Zulu version or the block list contents.
- Assuming the regular October builds include the fix. For upstream OpenJDK, Oracle and Temurin, the regular October builds were made from tags that predate the eMudhra change. The fixed upstream releases carry the 0.2 suffix.
- Editing the block list in a text editor. Azul warns this can make Java ignore the whole list. Copy the file as a binary.
- Patching the JDK and forgetting jlink output. A jlink runtime takes its file from the jmods at link time. Copy the file into each runtime, or relink from a fixed JDK.
- Updating Zulu to a build without the fix after applying the workaround. Azul notes this restores the original file. Reapply, or move to a fixed build.
- Not restarting, or reusing old CRaC checkpoints. The running JVM keeps the old list. So do existing checkpoints.
- Testing only one of the tracker hosts. The cross-sign path and the eMudhra path are separate certificates. Test both, plus the two "noct" hosts.
- Overwriting your own block list entries. The OpenJDK advisory says that if you have added entries to
blocked.certs, back it up and re-add them to the new file.
What would have helped
Practices any team can use
An inventory of Java runtimes, not just Java applications. This week's question is "which JDK builds from which vendors run where." A list of runtime vendor, version and location per service maps straight onto the vendor table above.
Rebuild and redeploy on a short loop. Every fixed build in this post is a base image or runtime bump. Weekly rebuilds make an out-of-cycle fix a routine merge.
A post-deploy TLS check in CI. A tiny check like TlsCheck.java, pointed at known-bad hosts when an incident provides them, proves the deployed runtime rejects them. It also catches the restart and jlink mistakes above.
For the broader background, see our notes on certificate authority compromise risks and using SBOMs to find affected products fast.
Zero-Day Discovery and Gold
Safeguard's Zero-Day Discovery looks for previously unknown flaws before a CVE exists, in an agentic mode and a deterministic scanner mode, across seven package ecosystems, and issues findings as SGZ advisories before they reach public CVE databases. It hunts code flaws in packages. A CA's weak keys are not a package code flaw, and JDK runtimes and trust stores are not what it inspects.
Gold Open Source at gold.safeguard.sh is free with no login: searchable CVE intelligence with CVSS, EPSS, KEV status, affected and fixed versions and a recommended safe version, plus a free read API and a GitHub Action for CI gates. Gold Registry at registry.safeguard.sh offers hardened drop-in components and container images held to zero exploitable critical or high CVEs, built to SLSA L3+, signed with Sigstore and published with evidence pages.
We are not saying Gold carried a Java image with the eMudhra block list before the JDK vendors shipped one. The habit that helps is the same as in every incident this month: pull patched, signed base images from a curated source and rebuild fast when upstream moves.
Where Safeguard fits
- Knowing which JDKs you run. Safeguard's SBOM generation and analysis (SPDX and CycloneDX) and its dependency inventory cover repos, container images and SBOM files:
safeguard scan --dir .,safeguard scan --image IMAGEorsafeguard scan --sbom FILE, with JSON results under./output. Where a JDK arrives as a package in an image, the platform shows which projects contain that component and version, so "which images still carry a pre-fix Java runtime" becomes a lookup. - Holding the line. Policies and gates evaluated in the platform can stop builds that still carry an outdated runtime package once you decide which versions are acceptable.
- Making the change. The Safeguard CLI assistant can bump a base image tag, add a reviewed
COPYof a block list file to a Dockerfile, and run the rebuild and tests, with your approval of each command.safeguard execruns one non-interactive turn for CI. Autonomous remediation can open fix PRs for version bumps; it ships off by default.
Where it does not help: Safeguard does not read certificates, keystores or block list files, so steps 3 to 5 stay manual. A JDK unpacked from a tarball, or bundled inside a vendor product, may not appear as a package at all. Safeguard cannot see a CA's key ceremony and cannot tell you whether anyone used a recovered key against you. No scanner would have prevented this incident.
Open questions
- Temurin, Corretto and Microsoft builds. We found no statement on 23 October. Watch each vendor's release notes for a build with JDK-8395142 or an eMudhra note, and use step 3 to check whatever you run.
- OpenJDK 11u and 8u releases. The change is committed to jdk11u and jdk8u, but we found no release tag containing it. Oracle's own 11.0.33.0.2 and 8u511 b32 are out.
- Red Hat portable builds. Red Hat says portable OpenJDK builds will be updated separately. No fixed build was listed when we checked.
- The ops.java pages. Oracle's alert and the OpenJDK advisory point to pages and block list downloads at ops.java, which returned access errors to our requests on 21 and 23 October. We could not compare those files with Azul's.
- Root removal in Java. The JDK fix blocks intermediates. Whether vendors later remove emSign ECC Root CA - G3 from
cacerts, as browsers are doing, is not stated in any page we read.
FAQ
Is there a Java fix for the eMudhra compromise now?
Yes. Oracle and Azul shipped fixed builds on 21 October 2026, and upstream OpenJDK tagged 0.2 releases for the 27, 25, 21 and 17 lines. We found nothing from other vendors on 23 October.
Which Oracle JDK versions include the block?
Per Oracle's release notes, all dated 21 October: 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2 and 8u511 b32 (full version string 1.8.0_511-b32). The regular October CPU builds released on 20 October do not mention it.
Which Azul Zulu versions include it?
The thirteen builds in the Azul table above, from Zulu 27.30.107 down to 6.83.0.108. Zulu 7 and 6 are SA builds only.
Can I apply the fix without upgrading?
On Zulu, yes: Azul's workaround replaces the block list file, with published SHA-256 values and scripts. The OpenJDK advisory describes the same file replacement for standalone OpenJDK runtimes, or turning on revocation checking. Restart every JVM afterwards.
Do I still need to delete the emSign and AAA roots from cacerts?
Not on a runtime that has the block list. The fix blocks all sixteen intermediate certificates, so both trust paths fail while other chains under those roots keep working. If you removed roots as an emergency step, keep or reverse that choice deliberately.
Why is my Zulu JDK version string the same as before?
Azul's PSU respins keep the JDK version of the regular October build they are based on, for example 21.0.13+9 for Zulu 21.54. Check the Zulu version, or count the fingerprints in the block list.
Does the fix cover signed JARs?
Yes, according to Oracle: jarsigner -verify -strict fails for a JAR signed through a chain containing one of the blocked certificates. The two CS intermediates are the code signing CAs.
My Temurin or Corretto image was rebuilt this week. Is it fixed?
Do not assume so. Their October releases did not mention eMudhra on the pages we checked, and upstream added the change after the regular October tags. Pull the block list from the image and count the fingerprints, as in step 6.
What about Java on RHEL, Debian or Ubuntu?
The OpenJDK advisory says distribution OpenJDK packages there most likely use the operating system's certificates, so the ca-certificates update is what counts. Red Hat had not listed fixed errata on 23 October; the tracker lists fixed ca-certificates versions for several distributions and a resync command for Debian's Java store.
Does Safeguard detect the bad certificates?
No. Safeguard does not inspect certificates or trust stores. It helps you inventory which JDK packages and versions your images and projects carry, so you know where to run the checks in this post.
Fix it without waiting for upstream
For the eMudhra fix, the JDK vendors did ship, in hours. The hard part is getting a fixed runtime into every image and service you run, which is the first gap below.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would have helped
The CLI demo shows the assistant fixing a lodash CVE: it reads the finding and the advisory, asks before each command, edits package.json, runs install and tests with your approval, and pushes nothing. For this update you would ask the same assistant to move a Java Dockerfile to a fixed base, or add a reviewed COPY of Azul's block list file for a Zulu image, then rebuild and run the fingerprint count from step 6. It asks before every command.
Click through it at your own pace, or open it full screen.
The local runner demo shows setting up the runner on your own machine, approving it with its device code, then scanning from the terminal. Here you would scan each Java image to see which runtime packages and versions it carries, then pair that inventory with the block list check, which Safeguard does not do for you.
Click through it at your own pace, or open it full screen.
The mobile app demo shows a real Android session: you send work to a computer running the CLI and approve each command on the phone with Allow once, Allow for turn or Deny. The same flow lets an on-call engineer approve a base image rebuild for a Java service from a phone, one command at a time.
Click through it at your own pace, or open it full screen.
To inventory the Java runtimes across your images before you start, download Safeguard and follow the CLI docs.
Quick check
You upgraded a Zulu 21 install and java -version still says 21.0.13+9. Did the upgrade work?
Possibly. Azul's PSU respin 21.54.107 keeps JDK version 21.0.13+9, the same as the regular October build. Check the Zulu version in the runtime name, or count the sixteen fingerprints in lib/security/blocked.certs, then confirm the JVM restarted after the change.
You replaced blocked.certs, the hash matches Azul's value, and the aaa test host still connects. What is the likely cause?
The JVM you tested started before you replaced the file, or it uses a different Java installation, such as a jlink runtime or a bundled JRE. Check java.home for the running process and its start time, restart it, and test again.
Sources
- Azul: Out-of-Cycle, October 21, 2026 Update Release Notes
- Azul: Workaround for the eMudhra CA certificate compromise
- Foojay.io: Azul Zulu October 2026 Quarterly Update: 53 CVEs, Then a Zero-Day One Day Later (23 October 2026)
- Oracle Security Alert Advisory: CVE-2026-91403
- Oracle: JDK 27.0.1.0.2 Release Notes
- Oracle: JDK 25.0.5.0.2 Release Notes
- Oracle: JDK 21.0.13.0.2 Release Notes
- Oracle: JDK 17.0.21.0.2 Release Notes
- Oracle: JDK 11.0.33.0.2 Release Notes
- Oracle: JDK 8u511 b32 Release Notes
- Oracle: JDK 8u511 Release Notes
- Oracle: JDK 25.0.5 Release Notes
- Oracle Critical Patch Update Advisory, October 2026
- OpenJDK Vulnerability Advisory: 2026/10/21
- OpenJDK commit 22bc735: 8395142 CA Enhancements
- OpenJDK source: blocked.certs.pem
- OpenJDK jdk25u repository
- OpenJDK jdk21u repository
- OpenJDK jdk17u repository
- OpenJDK jdk11u repository
- OpenJDK jdk8u repository
- Eclipse Adoptium news
- Eclipse Temurin release notes
- Eclipse Temurin 25 binaries releases
- Amazon Corretto 25 releases
- Amazon Corretto 21 changelog
- Amazon Corretto 17 changelog
- AWS security bulletins
- Microsoft Build of OpenJDK release notes
- Microsoft Build of OpenJDK downloads
- Red Hat: CVE-2026-91403
- Red Hat RHSB-2026-012: Certificate compromise, eMudhra
- Mozilla Security Blog: Protecting Firefox users following the compromise of eMudhra intermediate certificates
- eMudhra incident tracking and test site (Dennis Jackson)
Last reviewed: 23 October 2026. This is a developing story; check the linked advisories for the latest status.