Safeguard
Supply Chain Security•

eMudhra Java Fix Update: JDK Vendor Builds and Workarounds

Azul, Oracle and OpenJDK now ship Java builds that block the eight eMudhra intermediates. See versions per vendor, the blocked.certs fix and how to verify.

Safeguard Security Team
37 min read

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.certs on JDK 8). The emSign and AAA Certificate Services roots stay in cacerts.
  • 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.

WhenWhat happenedSource
17 Oct, 20:06 UTCMozilla receives the report that keys for eight eMudhra intermediates are compromisedMozilla Security Blog
17 Oct, 22:59 UTCOneCRL update reaches all Firefox users with standard settingsMozilla Security Blog
19 OctIssue disclosed to downstream trust storesCommunity tracker
20 OctMozilla publishes its blog post; the tracker page is dated the same dayMozilla, tracker
20 OctOracle's October 2026 Critical Patch Update, Rev 1, with 55 Java SE patches and no eMudhra entryOracle CPU advisory
20 Oct, 21:35 UTCJDK-8395142 "CA Enhancements" authored in the OpenJDK mainline repositoryOpenJDK GitHub
21 OctOracle 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 releasedOracle
21 OctOpenJDK Vulnerability Advisory 2026/10/21 lists CVE-2026-91403 for JDK 8, 11, 17, 21, 25 and 27OpenJDK
21 OctAzul out-of-cycle Zulu release notes, revision 1.3, and the eMudhra workaround pageAzul
21 Oct, 17:06 UTCJDK-8395142 committed to OpenJDK mainlineOpenJDK GitHub
21 Oct, 19:25 UTCJDK-8395142 lands in the jdk27u repositoryOpenJDK GitHub
22 Oct, 15:17 UTCJDK-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.2OpenJDK GitHub
22 Oct, 19:08 UTCJDK-8395142 lands in jdk11uOpenJDK GitHub
22 Oct, 19:40 UTCJDK-8395142 lands in jdk8uOpenJDK GitHub
22 OctTracker adds two "No CT" test chains whose leaf certificates were never logged to Certificate TransparencyCommunity tracker
23 Oct, 02:10Red Hat updates RHSB-2026-012; status still "Ongoing"Red Hat
23 Oct, 05:42 to 05:59 UTCAmazon Corretto October releases appear on GitHub; changelogs do not mention eMudhraCorretto 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 versionUpdate typeJDK versionJavaFX version
27.30.107 (CA), 27.30.108 (SA)PSU27.0.1+927.0.1+101
25.38.107 (CA), 25.38.108 (SA)PSU25.0.5+825.0.5+100
25.37.114 (SA)CPU25.0.4.1.101+125.0.4.0.101+102
21.54.107 (CA), 21.54.108 (SA)PSU21.0.13+923.0.9+102
21.53.112 (SA)CPU21.0.12.1.101+123.0.8.0.101+101
17.70.111 (CA), 17.70.112 (SA)PSU17.0.21+922.0.11+103
17.69.112 (SA)CPU17.0.20.1.101+122.0.10.0.101+101
11.92.109 (CA), 11.92.110 (SA)PSU11.0.33+919.0.17+102
11.91.112 (SA)CPU11.0.32.1.101+119.0.16.0.101+101
8.98.0.107 (CA), 8.98.0.108 (SA)PSU8u512-b088u512-b02
8.97.0.110 (SA)CPU8u511-b018u511-b03
7.89.0.110 (SA)CPU7u521-b01N/A
6.83.0.108 (SA)CPU6b191N/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:

  1. 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.
  2. Do not open it in a text editor. Azul warns that some editors add an invisible marker that makes Java ignore the whole list.
  3. Find the file to replace in the installation's lib/security directory. Azul lists default paths for its APT, DEB, RPM, macOS and Windows MSI installs, and says to add jre/ before lib/security on a Zulu 8 JDK. For anything else, run that installation's java -XshowSettings:properties -version and use the java.home value. If the directory has neither blocked.certs nor blacklisted.certs, Azul asks you to contact its support.
  4. Back up, then copy. Keep the original as a .bak-emudhra copy 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.
  5. Restart every Java application that uses the installation, including Windows services such as application servers.
  6. 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:

FilePlatformSHA-256 (as published by Azul)
emudhra-block-unix.certsLinux, macOS, containers2596bb6dda83c66d96c5a252d7b2ae1f24cc1ae3f1890223b4f3591a8d52bf10
emudhra-block-windows.certsWindows101200f8ff64a4375a03601cf0200d0f9fec449d1a173aaf1459a5765ae7e5ae

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 COPY of 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/security after 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.

VendorStatus on 23 Oct 2026Versions or detailWhere we looked
Azul ZuluOut-of-cycle builds and workaround published 21 Oct 2026Zulu 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.108Azul release notes and workaround page
Oracle JDKFixed builds and Security Alert published 21 Oct 202627.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 CPUNo eMudhra entryCPU Rev 1 dated 20 Oct; 55 Java SE patches; eMudhra handled by the separate Security AlertOracle CPU advisory, October 2026
OpenJDK (upstream)Change committed and advisory publishedJDK-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 foundOpenJDK Vulnerability Advisory 2026/10/21; OpenJDK GitHub repositories
Eclipse Temurin (Adoptium)No statement found on 23 Oct 2026Latest GA releases listed: jdk-25.0.5+8, jdk-21.0.13+9, jdk-17.0.21+9; no 0.2 builds listedadoptium.net news and release notes; Adoptium API; Temurin GitHub releases
Amazon CorrettoNo statement found on 23 Oct 2026October 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-8395142Corretto GitHub releases and changelogs; AWS security bulletins
Microsoft Build of OpenJDKNo statement found on 23 Oct 2026Release notes page listed no October 2026 releaseMicrosoft Learn release notes and download page; Microsoft Java blog feed
Red Hat build of OpenJDKAnalysis published; no fixed build listedNon-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 separatelyRed 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

ItemValueSource
CVE for JavaCVE-2026-91403Oracle 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 vectorAV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N, marked preliminaryRed Hat CVE page
OpenJDK changeJDK-8395142 "CA Enhancements"OpenJDK GitHub; Azul release notes
Oracle release note IDsJDK-8395555 (11 and later lines), JDK-8395593 (8u511 b32), both "not public"Oracle release notes
Red Hat Bugzilla2558584, "OpenJDK: Distrust eMudhra intermediate CA certificates due to security concerns"Red Hat CVE page
RHEL ca-certificates CVECVE-2026-114406RHSB-2026-012
Other ecosystem CVEs named by Red HatCVE-2026-111943 (Go), CVE-2026-113812 (Perl Mozilla::CA)RHSB-2026-012
Mainline commit22bc7357ce6bc5f1ed2f1e83e0544b2c25f781d4, authored 2026-10-20T21:35:46Z, committed 2026-10-21T17:06:26ZOpenJDK GitHub
Files changed upstreamblocked.certs.pem (+430 lines), BlockedCertsConverter.java, CheckBlockedCerts.java testOpenJDK 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 CNIssuer CNSerial (hex)SHA-256 fingerprintNot after
EM DV TLS CA - G3BemSign Root TLS CA - G3A4AEE678F23362B4C0E460B772F21442C4ACCD12C4F59597925E1A08A7A90102608543809308D50EC427E118BA149328 Apr 2040
EM DV TLS CA - G3CemSign Root TLS CA - G3588B2E3C2BB8CDA13E1A12092543210164D7CEAE5BB909C272AF151FF44B1177AE9B47D9424B94F1D9558C30934D1928 Apr 2040
EM EV TLS CA - G3BemSign Root TLS CA - G3C7C41EFE92D825F05EAE841A4A82C1E7568FE6E12331F4FD7DE61DA4C7559D0F8EB192A218D4741A3BA7518433383828 Apr 2040
EM EV TLS CA - G3CemSign Root TLS CA - G38009928A64107601AF05FA2F19F109432EC25F0D28DE9006D97BF752F17BBB2CD41F669933FCB072D9A1148D0261F328 Apr 2040
EM OV TLS CA - G3BemSign Root TLS CA - G36CADA367FB1C100088120EA202D56898B896625C0C230ADEEC3EB2CF6AAD5001ECF9156A68644E82374CE5833BC25B28 Apr 2040
EM OV TLS CA - G3CemSign Root TLS CA - G3296926C227A3A1526392B19482A504CB6E15165AC802E9B3F993F16C25D41F4E81C21EBDE71AE1B012AC00BF9C7C3F28 Apr 2040
EM OV CS CA - G3BemSign Root CS CA - G37818933F8F85B4619A2B35FBA83D0A9E39DE2881273ACC225A149C72BA3E0F51424963669AB633EE1DC7DF5DB067B428 Apr 2040
EM OV CS CA - G3CemSign Root CS CA - G3544B7F922C31AE220A4A922916F6E64B2460A466F95FD40113BCDCCA2CEB29B3B093921DE45474DA7DF48874C630B128 Apr 2040
EM DV TLS CA - G3BAAA Certificate ServicesA024FDF4BA665C785CE4A020483858B745A883F349AEDFD5F3A649B5498FFB121712BA8B448F3F2A91DBC5A766FCDDBE31 Dec 2028
EM DV TLS CA - G3CAAA Certificate Services91F347F1A5B7D39962B95E0EE4E299D162B7F9868263F72F6911FC78CEAF72C1979158B7368BF648683BB2AA39B02E7231 Dec 2028
EM EV TLS CA - G3BAAA Certificate ServicesD8F8685E4F2BD9D82402A85A1C1EB731579480AEA166290BD3C643589E795FC0D0E54E86505D180F1DFF99EFD319951231 Dec 2028
EM EV TLS CA - G3CAAA Certificate Services05F078752DECE7A1BB8595D303167171FD9D5C2DBBD4995AB69B8D50C439D9527B00529199C2FD01B2174EB58F07021F31 Dec 2028
EM OV TLS CA - G3BAAA Certificate ServicesE94223BDE92F914E5AB9ACABFDAC37105F1DED4DD590AF74631290CF073B122A2AAC6A1FA479778A0BD43579BD83269931 Dec 2028
EM OV TLS CA - G3CAAA Certificate Services8D5A4811939EF447D77111CDD9849AE97485B51C0ED192878FA1D2F948FB529AE1842CC5086C4B67F7BE5B2039DE948931 Dec 2028
EM OV CS CA - G3BAAA Certificate Services41E32B73AC185D6CE0D7480BACF84E69A496E23AC0CAB8155FC9B117B97EAE368EFCBB9041AEC8804D5A308D2D01C2D831 Dec 2028
EM OV CS CA - G3CAAA Certificate ServicesD6A5EF613B390F32EF9CDF349F77284184112972B8E59D14560AE7E7119654474AAD119990CF3722BFC1E3B91615E1FD31 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:

  • emsigneccrootcag3 stays in cacerts, 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 in cacerts, 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, and jssecacerts files, are separate from cacerts. 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 comodoaaaca on 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 IMAGE or safeguard 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 COPY of a block list file to a Dockerfile, and run the rebuild and tests, with your approval of each command. safeguard exec runs 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 situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull 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

Last reviewed: 23 October 2026. This is a developing story; check the linked advisories for the latest status.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.