Lotu Radar About

The eMudhra Certificate Authority Compromise: What It Means for TeamCity

JetBrains Blog Developers & Open Source Score 7/10

Summary

Summary In October 2026, the private keys of eight intermediate certificate authorities operated by eMudhra were found to be weak and recoverable from public data. According to eMudhra’s official statement, none of the affected intermediate CAs had issued end-entity (leaf) certificates, and eMudhra is not aware of evidence that the weak keys were recovered or exploited before the issue was disclosed. The […]

Original Text

Summary

In October 2026, the private keys of eight intermediate certificate authorities operated by eMudhra were found to be weak and recoverable from public data. According to eMudhra’s official statement, none of the affected intermediate CAs had issued end-entity (leaf) certificates, and eMudhra is not aware of evidence that the weak keys were recovered or exploited before the issue was disclosed.

The issue is not a vulnerability in TeamCity itself. However, the trust stores maintained by other software components (primarily the Java runtime) that TeamCity relies on may continue to trust the compromised certificates. Starting with versions 2026.2.2 and 2026.1.6, TeamCity shows a health report if the installation still trusts affected certificates, along with remediation steps.

Recommended actions:

TeamCity On-Premises: Review server and build agent installations and apply the necessary fixes according to the instructions below. Upgrade to v2026.2.2 or v2026.1.6 for an updated Java runtime for the Windows agent installer, updated Docker images, and the health report, or follow the instructions below to apply the same fixes to the current installation.

TeamCity Cloud: TeamCity Cloud has already been updated. Certificates uploaded to TeamCity must be reviewed as described in Certificates uploaded to TeamCity below. Self-hosted build agents must also be reviewed according to the instructions below.

Details

On October 17, 2026, the private keys of eight eMudhra intermediate CAs, six for TLS and two for code signing, were reported as compromised. This is an industry-wide certificate authority incident, not an issue specific to TeamCity. Certificates issued with these keys would look valid to any software that still trusts them.

Browser and OS vendors have released updates that block the compromised certificates, and systems are protected once they install them. Software with its own trust store, such as a Java runtime, keeps trusting the compromised certificates until that trust store is updated. TeamCity’s server and build agents use the trust store of their Java runtime.

TeamCity downloads are not signed by an eMudhra CA and are not affected.

What you need to do

1. Update the Java runtime

Identify the Java runtime used by each server node and agent, including any custom trust store set with javax.net.ssl.trustStore.

Check the Java vendor’s release notes for CVE-2026-91403 and CVE-2026-114820. For Amazon Corretto 21, the fixed build is 21.0.13.0.11 or later.

Update affected runtimes and restart each server node or agent.

Optional trust-store verification can identify affected certificates still present in a trust store. If upgrading is not feasible, follow the manual mitigation commands in the same section.

Removing AAA Certificate Services can disrupt unaffected services; test dependent connections before removing that root.

2. Update your TeamCity server and review uploaded certificates

The following server maintenance recommendations apply to TeamCity On-Premises installations. JetBrains patches TeamCity Cloud, but certificates uploaded to the service still require review.

Upgrade TeamCity if possible. Releases 2026.2.2 and 2026.1.6 add the health report, other product improvements, and fixes for other vulnerabilities. Existing agents require an independent review.

Update Java on every server node. Follow Update the Java runtime, even after upgrading TeamCity.

Redeploy Docker installations. Pull the patched 2026.2.2 or 2026.1.6 server image from Docker Hub once published, or rebuild the existing image using the server image instructions. Recreate the containers.

Review uploaded certificates. Use the health report or the certificate inspection commands below and then remove affected certificates through the Root project’s SSL / HTTPS Certificates page. Updating Java does not remove uploaded certificates.

Updating the TeamCity server does not update integrations or third-party software. Review those components separately as described in Review and update supporting infrastructure.

3. Update your TeamCity agents and review trusted certificates

Update Java on every build agent. Follow Update the Java runtime. TeamCity Cloud customers must also review the Java runtimes used by their self-hosted agents. The health report does not check agents.

Update Docker installations. Pull the patched 2026.2.2 or 2026.1.6 agent image from Docker Hub. Alternatively, rebuild the existing image using the same rebuild instructions as for the server image. Recreate the containers using the updated image.

Review agent certificates. Run the certificate inspection commands under Technical commands from /conf/trustedCertificates and remove any affected certificate files. Updating Java does not remove these certificates.

4. Review and update supporting infrastructure

Updating the server does not update integrations or third-party software. We recommend reviewing these components independently:

Operating systems and build tools: Apply vendor updates to OS trust stores, other Java runtimes, Git and MinGit, Python’s certifi, Node.js, and other tools with separate trust stores.

Custom images: Update the OS and tools inside each affected image, rebuild the image, and recreate the containers.

Connected services: Replace eMudhra certificates used by VCS hosts, package registries, and other services through eMudhra’s migration process.

Technical commands

Each script defines its environment variables at the top:

TEAMCITY_JRE: Defaults to JAVA_HOME; change it if TeamCity runs on another JRE or JDK.

TC_TRUSTSTORE: Set to any custom javax.net.ssl.trustStore (JDK 8 default: jre/lib/security/cacerts).

TC_STOREPASS: Change it if the password differs.

TC_CERT_DIR: The certificate file to inspect, where indicated.

Optional trust-store verification

Please note the result applies only to the selected trust store. The commands do not inspect blocked.certs.

Linux and macOS (Bash or zsh):

( export TEAMCITY_JRE="${TEAMCITY_JRE:-$JAVA_HOME}" export TC_TRUSTSTORE="$TEAMCITY_JRE/lib/security/cacerts" export TC_STOREPASS='changeit' keytool="${TEAMCITY_JRE:?Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use}/bin/keytool" [ -x "$keytool" ] || { echo "ERROR: keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin/ and lib/)." >&2; exit 1; } output=$("$keytool" -J-Duser.language=en -list -v \ -keystore "$TC_TRUSTSTORE" -storepass:env TC_STOREPASS) || { echo "ERROR: Certificate check failed." >&2; printf '%s\n' "$output" >&2; exit 1; } awk ' /^Alias name:/ { alias=$0 } /86:A1:EC:BA:08:9C:4A:8D|D7:A7:A0:FB:5D:7E:27:31|7D:D7:8D:5F:4F:13:45:9A|F2:ED:AA:FF:3D:9B:70:1F|40:F6:AF:03:46:A9:9A:A1|1A:A0:C2:70:9E:83:1B:D6|CN=EM (DV|OV|EV) (TLS|CS) CA - G3/ { found=1; print alias; print } END { print found ? "ACTION REQUIRED: this trust store still trusts compromised eMudhra certificates (listed above). Update the Java runtime or apply the manual mitigation." \ : "OK: no compromised eMudhra certificates found in this trust store. No action is needed for it." } ' <<< "$output" )

Windows (PowerShell):

& { $ErrorActionPreference = 'Stop' if (-not $env:TEAMCITY_JRE) { $env:TEAMCITY_JRE = $env:JAVA_HOME } $env:TC_TRUSTSTORE = "$env:TEAMCITY_JRE\lib\security\cacerts" $env:TC_STOREPASS = 'changeit' if (-not $env:TEAMCITY_JRE) { throw 'Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use.' } $keytool = "$env:TEAMCITY_JRE\bin\keytool.exe" if (-not [IO.File]::Exists($keytool)) { throw "keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin\ and lib\)." } $prev = $ErrorActionPreference; $ErrorActionPreference = 'Continue' $output = & $keytool '-J-Duser.language=en' -list -v -keystore "$env:TC_TRUSTSTORE" -storepass:env TC_STOREPASS 2>&1 $ErrorActionPreference = $prev if ($LASTEXITCODE -ne 0) { throw "ERROR: Certificate check failed. $output" } $pattern = '86:A1:EC:BA:08:9C:4A:8D|D7:A7:A0:FB:5D:7E:27:31|7D:D7:8D:5F:4F:13:45:9A|F2:ED:AA:FF:3D:9B:70:1F|40:F6:AF:03:46:A9:9A:A1|1A:A0:C2:70:9E:83:1B:D6|CN=EM (DV|OV|EV) (TLS|CS) CA - G3' $alias = '' $found = $false foreach ($line in $output) { if ($line -match '^Alias name:') { $alias = $line } if ($line -match $pattern) { $found = $true; $alias; $line } } if ($found) { 'ACTION REQUIRED: this trust store still trusts compromised eMudhra certificates (listed above). Update the Java runtime or apply the manual mitigation.' } else { 'OK: no compromised eMudhra certificates found in this trust store. No action is needed for it.' } }

Certificates uploaded to TeamCity

The health report in versions 2026.2.2 and 2026.1.6 lists affected server certificates. For manual inspection, check custom certificates and identify the affected ones.

Set path to the directory with custom certificates (TC_CERT_DIR) to the following and run the command:

Server: /config/projects/_Root/pluginData/trustedCertificates

Agent: /conf/trustedCertificates

Linux and macOS (Bash or zsh):

( export TEAMCITY_JRE="${TEAMCITY_JRE:-$JAVA_HOME}" export TC_CERT_DIR="${TC_CERT_DIR:-/path/to/trusted/certificates}" keytool="${TEAMCITY_JRE:?Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use}/bin/keytool" [ -x "$keytool" ] || { echo "ERROR: keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin/ and lib/)." >&2; exit 1; } [ -d "$TC_CERT_DIR" ] || { echo "ERROR: directory not found: $TC_CERT_DIR. Either no custom certificates have been added yet (TeamCity creates the directory on the first upload), or TC_CERT_DIR is incorrect (server: <TeamCity Data Directory>/config/projects/_Root/pluginData/trustedCertificates, agent: <agent home>/conf/trustedCertificates)." >&2; exit 1; } found=0 while IFS= read -r f; do output=$("$keytool" -J-Duser.language=en -printcert -v -file "$f") || { echo "ERROR: Cannot read $f." >&2; printf '%s\n' "$output" >&2; exit 1; } if grep -Eq '86:A1:EC:BA:08:9C:4A:8D|D7:A7:A0:FB:5D:7E:27:31|7D:D7:8D:5F:4F:13:45:9A|F2:ED:AA:FF:3D:9B:70:1F|40:F6:AF:03:46:A9:9A:A1|1A:A0:C2:70:9E:83:1B:D6|CN=EM (DV|OV|EV) (TLS|CS) CA - G3' <<< "$output"; then echo "AFFECTED: $f"; found=1 fi done < <(find "$TC_CERT_DIR" -maxdepth 1 -type f) [ "$found" = 1 ] && echo "ACTION REQUIRED: the files listed above are compromised eMudhra certificates. Remove them (server: SSL/HTTPS Certificates page; agent: delete the files)." || echo "OK: no compromised eMudhra certificates found in $TC_CERT_DIR. No action is needed." )

Windows (PowerShell):

& { $ErrorActionPreference = 'Stop' if (-not $env:TEAMCITY_JRE) { $env:TEAMCITY_JRE = $env:JAVA_HOME } if (-not $env:TC_CERT_DIR) { $env:TC_CERT_DIR = 'C:\path\to\trusted\certificates' } if (-not $env:TEAMCITY_JRE) { throw 'Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use.' } $keytool = "$env:TEAMCITY_JRE\bin\keytool.exe" if (-not [IO.File]::Exists($keytool)) { throw "keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin\ and lib\)." } if (-not [IO.Directory]::Exists($env:TC_CERT_DIR)) { throw "ERROR: directory not found: $env:TC_CERT_DIR. Either no custom certificates have been added yet (TeamCity creates the directory on the first upload), or TC_CERT_DIR is incorrect (server: <TeamCity Data Directory>\config\projects\_Root\pluginData\trustedCertificates, agent: <agent home>\conf\trustedCertificates)." } $pattern = '86:A1:EC:BA:08:9C:4A:8D|D7:A7:A0:FB:5D:7E:27:31|7D:D7:8D:5F:4F:13:45:9A|F2:ED:AA:FF:3D:9B:70:1F|40:F6:AF:03:46:A9:9A:A1|1A:A0:C2:70:9E:83:1B:D6|CN=EM (DV|OV|EV) (TLS|CS) CA - G3' $found = $false foreach ($file in Get-ChildItem -LiteralPath $env:TC_CERT_DIR -File) { $output = & $keytool '-J-Duser.language=en' -printcert -v -file $file.FullName if ($LASTEXITCODE -ne 0) { throw "ERROR: Cannot read $($file.FullName). $output" } if ($output -match $pattern) { "AFFECTED: $($file.FullName)"; $found = $true } } if ($found) { 'ACTION REQUIRED: the files listed above are compromised eMudhra certificates. Remove them (server: SSL/HTTPS Certificates page; agent: delete the files).' } else { "OK: no compromised eMudhra certificates found in $env:TC_CERT_DIR. No action is needed." } }

Manual mitigation commands

Before execution, make sure TEAMCITY_JRE in the current terminal points to the runtime actually running the TeamCity component:

Server: Consult this configuration reference.

Agents: Check teamcity.agent.jvm.java.home on the agent’s Parameters tab, as described in the Java Update Guide.

Copy lib/security/blocked.certs from a JDK containing the fix for CVE-2026-91403 to the same location in the runtime in use. Java 8 uses jre/lib/security/blacklisted.certs, while some Java 11 and 13 builds also use blacklisted.certs, so verify the path before copying.

Back up the trust store. Removing AAA Certificate Services can disrupt unaffected services; test dependent connections first.

Run the command below. It uses the same script header as the verification commands above, finds the affected roots listed above by fingerprint, and deletes them. Running it again is safe.

Linux and macOS (Bash or zsh):

( export TEAMCITY_JRE="${TEAMCITY_JRE:-$JAVA_HOME}" export TC_TRUSTSTORE="$TEAMCITY_JRE/lib/security/cacerts" export TC_STOREPASS='changeit' keytool="${TEAMCITY_JRE:?Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use}/bin/keytool" [ -x "$keytool" ] || { echo "ERROR: keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin/ and lib/)." >&2; exit 1; } [ -w "$TC_TRUSTSTORE" ] || { echo "ERROR: cannot write to $TC_TRUSTSTORE (missing or no permission). Run with sudo or as the owner of the Java installation." >&2; exit 1; } output=$("$keytool" -J-Duser.language=en -list -v \ -keystore "$TC_TRUSTSTORE" -storepass:env TC_STOREPASS) || { echo "ERROR: Certificate check failed." >&2; printf '%s\n' "$output" >&2; exit 1; } affected=$(awk ' /^Alias name:/ { alias=substr($0, 13) } /SHA256: (86:A1:EC:BA:08:9C:4A:8D:3B:BE:27:34:C6:12:BA:34:1D:81:3E:04:3C:F9:E8:A8:62:CD:5C:57:A3:6B:BE:6B|D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4|7D:D7:8D:5F:4F:13:45:9A:83:DF:F9:AB:BB:A6:2E:DB:AF:6F:2D:10:2B:F2:57:FD:71:2F:4D:9F:27:46:ED:8D|F2:ED:AA:FF:3D:9B:70:1F:B4:D1:4C:9F:28:5F:8C:0B:AD:90:FC:3B:CC:1F:A0:7D:47:F4:71:8E:DA:BA:34:A5|40:F6:AF:03:46:A9:9A:A1:CD:1D:55:5A:4E:9C:CE:62:C7:F9:63:46:03:EE:40:66:15:83:3D:C8:C8:D0:03:67|1A:A0:C2:70:9E:83:1B:D6:E3:B5:12:9A:00:BA:41:F7:EE:EF:02:08:72:F1:E6:50:4B:F0:F6:C3:F2:4F:3A:F3)/ { print alias } ' <<< "$output") [ -n "$affected" ] || { echo "OK: this trust store contains no compromised eMudhra roots. Nothing to delete."; exit 0; } while IFS= read -r alias; do echo "Deleting: $alias" "$keytool" -delete -alias "$alias" -keystore "$TC_TRUSTSTORE" -storepass:env TC_STOREPASS || exit 1 done <<< "$affected" echo "DONE: removed the compromised root certificates listed above. Restart the TeamCity server node or agent, then run the verification again." )

Windows (PowerShell):

& { $ErrorActionPreference = 'Stop' if (-not $env:TEAMCITY_JRE) { $env:TEAMCITY_JRE = $env:JAVA_HOME } $env:TC_TRUSTSTORE = "$env:TEAMCITY_JRE\lib\security\cacerts" $env:TC_STOREPASS = 'changeit' if (-not $env:TEAMCITY_JRE) { throw 'Set TEAMCITY_JRE or JAVA_HOME to the Java home directory of the runtime in use.' } $keytool = "$env:TEAMCITY_JRE\bin\keytool.exe" if (-not [IO.File]::Exists($keytool)) { throw "keytool not found at $keytool. TEAMCITY_JRE must be the Java home directory (the folder that contains bin\ and lib\)." } try { [IO.File]::Open($env:TC_TRUSTSTORE, 'Open', 'ReadWrite').Dispose() } catch { throw "ERROR: cannot write to $env:TC_TRUSTSTORE. Run PowerShell as Administrator or as the owner of the Java installation. ($($_.Exception.Message))" } $prev = $ErrorActionPreference; $ErrorActionPreference = 'Continue' $output = & $keytool '-J-Duser.language=en' -list -v -keystore "$env:TC_TRUSTSTORE" -storepass:env TC_STOREPASS 2>&1 $ErrorActionPreference = $prev if ($LASTEXITCODE -ne 0) { throw "ERROR: Certificate check failed. $output" } $roots = '86:A1:EC:BA:08:9C:4A:8D:3B:BE:27:34:C6:12:BA:34:1D:81:3E:04:3C:F9:E8:A8:62:CD:5C:57:A3:6B:BE:6B|D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4|7D:D7:8D:5F:4F:13:45:9A:83:DF:F9:AB:BB:A6:2E:DB:AF:6F:2D:10:2B:F2:57:FD:71:2F:4D:9F:27:46:ED:8D|F2:ED:AA:FF:3D:9B:70:1F:B4:D1:4C:9F:28:5F:8C:0B:AD:90:FC:3B:CC:1F:A0:7D:47:F4:71:8E:DA:BA:34:A5|40:F6:AF:03:46:A9:9A:A1:CD:1D:55:5A:4E:9C:CE:62:C7:F9:63:46:03:EE:40:66:15:83:3D:C8:C8:D0:03:67|1A:A0:C2:70:9E:83:1B:D6:E3:B5:12:9A:00:BA:41:F7:EE:EF:02:08:72:F1:E6:50:4B:F0:F6:C3:F2:4F:3A:F3' $alias = '' $aliases = foreach ($line in $output) { if ($line -match '^Alias name: (.+)$') { $alias = $Matches[1] } if ($line -match "SHA256: ($roots)") { $alias } } if (-not $aliases) { 'OK: this trust store contains no compromised eMudhra roots. Nothing to delete.'; return } foreach ($a in $aliases) { "Deleting: $a" $ErrorActionPreference = 'Continue' $result = & $keytool -delete -alias $a -keystore "$env:TC_TRUSTSTORE" -storepass:env TC_STOREPASS 2>&1 $ErrorActionPreference = $prev if ($LASTEXITCODE -ne 0) { throw "ERROR: Failed to delete $a. $result" } } 'DONE: removed the compromised root certificates listed above. Restart the TeamCity server node or agent, then run the verification again.' }

Afterwards, run the verification commands above to confirm the roots are gone. Restart the server node or agent after completing the mitigation. Include any custom trust stores in the review.

Security Bulletin

JetBrains’ assessment and guidance on the eMudhra Certificate Authority incident is available here.

Frequently asked questions

Is TeamCity affected?

Not directly. As a CI/CD system, TeamCity connects to multiple integrations and relies on Java runtimes, build tools, and other components with separate trust stores. These trust stores require independent review and updates, as described in What you need to do.

Do I need to upgrade?

Upgrading to 2026.2.2 or 2026.1.6 is recommended. These releases add the health report, other product improvements, and fixes for other vulnerabilities.

Upgrading TeamCity does not always update Java, so review the corresponding runtime using the Optional trust-store verification section above. If upgrading TeamCity is not currently an option, apply the mitigations described in If upgrading is not feasible above.

Is TeamCity Cloud affected?

TeamCity Cloud has already been updated, but customers must still check:

Self-hosted agents using TeamCity Agents, as described above.

Certificates uploaded to TeamCity, as described above.

Does the health report check build agents?

No. The health report checks the server nodes only. Check and fix build agents manually, as described in TeamCity Agents above.

Which TeamCity Docker images are affected?

Images for versions 2026.2.2 and 2026.1.6 are patched, so please update if possible. Older images can be patched as described in TeamCity Server and TeamCity Agents above, and then used to recreate the containers.

Support

For any questions regarding this issue, please get in touch with the TeamCity Support team by submitting a ticket. To report a security issue in TeamCity, please follow our Coordinated Disclosure Policy.

References

eMudhra Statement on Recent Certificate Security Incident

OpenJDK advisory (CVE-2026-91403)

Oracle security alert (CVE-2026-114820)

eMudhra Certificate Authority Incident: Status and Guidance for JetBrains Products

Developer ToolsIDESoftware

Lotu Radar provides attributed news summaries and links to the original publisher. Full reporting and copyright remain with the source.