← Back to Feed CACHED · 2026-10-21 18:16:01 · CACHE_KEY CVE-2026-111943
CVE-2026-111943 · CWE-295 · Disclosed 2026-10-21

Go crypto/x509 failure to distrust compromised eMudhra intermediate CA certificates with trivially weak keys

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Someone left the master key under a doormat made of the number 4, and every Go service in your fleet would have opened the door

CVE-2026-111943 tracks Go's crypto/x509 package failing to distrust eight eMudhra intermediate CA certificates whose private keys were generated with catastrophically low entropy during an April 2025 key ceremony. The private key values were single-byte integers — literally values like 4, 56, and 237 — on a P-384 curve that should produce 384-bit random numbers (~10¹¹⁵ possibilities). Anyone who examined the public certificate could recover the private key in milliseconds on commodity hardware. Six intermediates issued TLS certificates (DV, OV, EV) and two issued code-signing certificates, all cross-signed by Sectigo's AAA Certificate Services root. Go versions prior to 1.26.10 and 1.27.0 through 1.27.2 are affected. The fix adds a hard-coded SPKI denylist to crypto/x509.Verify(), returning x509: no valid chains built when a blocked intermediate appears in the chain. Crucially, installing a newer Go compiler does not protect running binaries — every Go application must be rebuilt with a patched toolchain.

No vendor CVSS was published by the Go team or NVD. Red Hat assigned CVSS:3.1 6.8 (Important) with AC:H/UI:R, which models browser-centric MitM. That underweights the real exposure: Go powers Kubernetes, Vault, Docker, Terraform, etcd, Prometheus, and thousands of headless API services that make TLS connections with zero user interaction. For those workloads, UI:N is correct, pushing the base to 7.4. Factor in the 17-month exposure window, the trivial key recovery, and two compromised code-signing intermediates, and the realistic severity for enterprise Go estates is HIGH at 7.5. Browsers are already protected — your headless Go services and CI/CD pipelines are the gap.

"Trivially weak CA keys let anyone forge trusted certs for Go services for 17 months"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Recover eMudhra intermediate private keys

The attacker downloads any of the eight compromised intermediate certificates from CT logs, CCADB, or cached copies. They compute the elliptic curve point multiplication d × G for integers 1 through 256 on the P-384 curve. When the result matches the certificate's public key, they have the private key. This takes under one second on any modern laptop. No specialized hardware, no brute-force cluster — a Python one-liner with cryptography suffices.
Conditions required:
  • Access to the public certificate (freely available via CT logs or CCADB)
  • Basic cryptographic tooling (OpenSSL, Python cryptography library)
Where this breaks in practice:
  • The keys have been publicly documented since October 17, 2026 — the 'secret' is out. This step has zero friction for any attacker.
STEP 02

Forge a TLS certificate for target domain

Using the recovered intermediate private key, the attacker creates a new end-entity certificate for any target domain (e.g., api.stripe.com, registry.npmjs.org, kube-apiserver.internal). They sign it with the compromised intermediate. The resulting chain is forged leaf → compromised eMudhra intermediate → Sectigo AAA root, which chains to a universally trusted root CA. Scott Helme confirmed this works against non-browser clients with default settings on Linux, macOS, and Windows.
Conditions required:
  • Recovered private key from Step 1
  • OpenSSL or equivalent for certificate generation
Where this breaks in practice:
  • Browsers with updated CRLSets/OneCRL will reject the chain immediately. This step only succeeds against non-browser TLS clients.
Detection/coverage: Certificate Transparency monitoring will flag unauthorized certificates if the attacker logs them — but CT logging is optional and attackers will skip it.
STEP 03

Establish man-in-the-middle position

The attacker positions themselves in the network path between the victim Go service and its intended server. Techniques include ARP spoofing on the local LAN, DNS cache poisoning, BGP hijacking, rogue WiFi access points, or compromise of an upstream proxy/CDN/DNS provider. For cloud workloads, compromising a cloud DNS zone or VPC routing table achieves the same effect. This is the primary friction point in the chain.
Conditions required:
  • Network proximity or control of routing/DNS infrastructure
  • Victim Go service connects to an external HTTPS endpoint over a path the attacker can intercept
Where this breaks in practice:
  • MitM positioning is non-trivial — requires network-level access or control of routing infrastructure
  • Enterprise networks with proper segmentation, DNSSEC, and monitoring make this harder
  • Cloud-native workloads communicating within a VPC over private endpoints are harder to intercept
Detection/coverage: Network anomaly detection (ARP anomalies, DNS response mismatches, unexpected BGP route changes). IDS/IPS signatures for ARP spoofing and DNS poisoning.
STEP 04

Present forged certificate to Go service

When the victim Go application initiates a TLS handshake to the target domain, the attacker intercepts and presents the forged certificate chain. If the Go binary was built with an unpatched toolchain (pre-1.26.10 or pre-1.27.3), crypto/x509.Verify() will accept the chain because the compromised intermediate is not in the denylist. The TLS session completes successfully. The attacker now has full read/write access to the encrypted channel.
Conditions required:
  • Victim application built with Go < 1.26.10 or 1.27.0-1.27.2
  • Victim's OS trust store has not independently removed the eMudhra root/intermediate
  • No certificate pinning or CT enforcement in the application
Where this breaks in practice:
  • OS-level trust store updates (ca-certificates, certctl) may block the chain independently of Go
  • Applications using certificate pinning are immune
  • Go applications rebuilt with patched toolchain are immune
Detection/coverage: Application-level TLS certificate logging (if enabled). Network security monitoring for certificate chain anomalies. Endpoint detection of unexpected certificate issuers.
STEP 05

Intercept or modify sensitive traffic

With the MitM established and trusted by the Go service, the attacker can read API keys, OAuth tokens, webhook payloads, secrets fetched from Vault, container image layers pulled from registries, Kubernetes API server responses, or any other data flowing through the connection. They can also modify responses — injecting malicious container images, altering Terraform state, or tampering with package downloads. For code-signing intermediates, forged signatures could make malware appear legitimately signed by eMudhra OV CS CA.
Conditions required:
  • Successful MitM from Steps 3-4
Where this breaks in practice:
  • Application-layer integrity checks (e.g., digest verification for container images, checksum validation for packages) catch modification
  • mTLS with client certificates not chaining to eMudhra prevents impersonation in both directions
Detection/coverage: SIEM correlation of unusual API patterns, integrity verification failures, unexpected code-signing certificate issuers in software deployment pipelines.
03 · Compensating Control

1
HIGH 7.5→MEDIUM 5.5
SEVERITY REDUCED
Update OS trust stores immediately — Deploy updated ca-certificates packages across all Linux hosts and containers (yum update ca-certificates on RHEL, apt-get install --only-upgrade ca-certificates on Debian/Ubuntu, apk upgrade ca-certificates-bundle on Alpine). On macOS, apply the latest security update. On Windows, the October 20 CTL update already blocks the intermediates. This breaks the chain at the trust anchor level regardless of the Go binary version. Per the noisgate mitigation SLA for HIGH, deploy within 30 days — but given the trivial key recovery and 17-month window, treat this as urgent and push within 72 hours.
2
HIGH 7.5→LOW 3.0
SEVERITY REDUCED
Rebuild all Go binaries with Go ≥1.26.10 or ≥1.27.3 — The Go denylist is a defense-in-depth layer that protects Go applications even if OS trust stores are stale, misconfigured, or missing (common in minimal container images like scratch and distroless). Audit your Go binary inventory: find / -type f -exec file {} + | grep 'Go BuildID' or check container SBOMs. Rebuild and redeploy. Per the noisgate remediation SLA for HIGH, complete within 180 days. Prioritize binaries in Kubernetes control plane, CI/CD pipelines, and secret-management integrations.
3
HIGH 7.5→LOW 2.5
SEVERITY REDUCED
Pin certificates or enforce CT in critical Go services — For your highest-value Go services (Vault agents, Kubernetes components, CI/CD runners), implement certificate pinning to known leaf or intermediate certificate SPKI hashes. Alternatively, configure Go's crypto/tls with a custom VerifyPeerCertificate callback that checks Certificate Transparency SCTs. This eliminates the forged-certificate vector entirely for pinned services, independent of trust store state.
4
HIGH 7.5→HIGH 7.5
Monitor for anomalous certificate issuers in TLS connections — Deploy network-level TLS inspection or endpoint logging that captures certificate chain details. Alert on any certificate chaining to eMudhra intermediates (issuer CN containing EM DV TLS, EM OV TLS, EM EV TLS, EM OV CS under emSign Root). If you see one, you have active exploitation. Integrate with SIEM for correlation.
What doesn't work
  • WAF / NGFW at the perimeter — this is a trust-store issue in the TLS client, not a network payload that a firewall can inspect or block. The forged certificate is structurally valid; only the trust anchor is wrong.
  • OCSP stapling alone — eMudhra revoked the intermediates, but Go's crypto/x509 does not check OCSP or CRL by default. Most Go applications have no revocation checking. The OS CRL/OCSP infrastructure is also inconsistently enforced on non-browser clients.
  • Rotating application-layer API keys — key rotation protects against credential reuse after interception, but does not prevent the MitM itself. The attacker can intercept the new keys too if the TLS channel remains compromised.
  • Network segmentation alone — while segmentation reduces MitM opportunities, it does not eliminate them. An attacker inside a network segment (post-compromise) can still ARP-spoof and intercept Go service traffic within that segment.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo confirmed exploitation. eMudhra states it is "not aware of any evidence that the weak keys were recovered or exploited by anyone before the issue was disclosed." No TLS certificates chaining to the six affected website intermediates appeared in Certificate Transparency logs before Chrome blocked the keys. However, the keys were trivially recoverable for 17 months (April 2025 – October 2026) and CT logging is not mandatory.
Proof of ConceptCryptographic proof demonstrated, not traditional exploit code. Security researcher Wayne submitted valid signed attestations proving private-key control for all eight certificates. Mozilla independently recovered the keys. Scott Helme published a detailed walkthrough at scotthelme.co.uk confirming forged certificates for api.stripe.com verified successfully on unpatched Linux, macOS, and Windows. No traditional exploit repo on GitHub or pocindex.io — the 'PoC' is trivial key recovery math, not a weaponized tool.
EPSS0.00145 (low percentile). EPSS models traditional software exploits poorly for CA trust issues — the exploitation pattern is fundamentally different from a CVE with a network-reachable code path.
KEV StatusNot listed on CISA KEV as of 2026-10-22. Given no confirmed exploitation, KEV listing is unlikely unless intelligence surfaces.
CVSS Vector (Red Hat)CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N = 6.8. Red Hat's UI:R models browser usage; for headless Go services UI:N is more accurate → 7.4. noisgate assesses 7.5 accounting for code-signing and supply-chain blast radius.
Affected VersionsGo stdlib crypto/x509: all versions before 1.26.10 and 1.27.0 through 1.27.2. Also affects: Python certifi < 2026.10.18, Node.js < 22.23.4 / 24.22.1 / 26.12.1, Mozilla NSS < 3.131.1, Rust webpki-roots < 1.0.10, and OS ca-certificates packages across RHEL, Ubuntu, Alpine, macOS.
Fixed VersionsGo 1.26.10, Go 1.27.3. Applications must be rebuilt — upgrading the Go toolchain alone is insufficient. OS trust stores: RHEL ca-certificates via RHSB-2026-012, Ubuntu/Debian via update-ca-certificates, Alpine via apk upgrade ca-certificates-bundle.
Compromised CertificatesEight eMudhra intermediates under emSign Root TLS CA - G3 and emSign Root CS CA - G3: EM DV TLS CA G3B/G3C, EM OV TLS CA G3B/G3C, EM EV TLS CA G3B/G3C (TLS), EM OV CS CA G3B/G3C (code signing). Private key values: 4, 56, 66, 115, 155, 156, 230, 237 on P-384.
Disclosure TimelineApril 30, 2025: Weak keys generated. May 2025: Sectigo cross-signs. October 17, 2026 20:06 UTC: Wayne reports to Mozilla. Same day: Chrome CRLSet block deployed. October 18: eMudhra revokes as cACompromise. October 19: Apple blocks. October 20: Microsoft blocks, Go releases 1.26.10/1.27.3. October 21: eMudhra public statement, Red Hat RHSB-2026-012.
DiscoverySecurity researcher Wayne discovered the flaw on October 17, 2026, while running checks against the Common CA Database (CCADB). Mozilla independently reproduced key recovery. Scott Helme published detailed technical analysis and confirmed forged certificate acceptance.

Sources.

  1. Red Hat CVE Page & CVSS Vector
  2. Red Hat Security Bulletin RHSB-2026-012
  3. Scott Helme — Eight Bits of Trust: eMudhra's CA Keys Cracked
  4. Threat Landscape — Go 1.27.3 Blocks Eight eMudhra Intermediate CAs
  5. SOCPrime — CVE-2026-111943 Analysis
  6. Cloudflare — eMudhra Certificate Compromise
  7. Help Net Security — eMudhra Private Keys Compromised
  8. Cross-Ecosystem Impact: Go, Python certifi, Node.js, Java
05 · The Call

Final Verdict
= UNCHANGED to HIGH (7.5/10)

Why this verdict

  • MitM prerequisite is real friction but not disqualifying. The attack requires network positioning (AC:H), which eliminates drive-by exploitation. However, nation-state actors, compromised cloud DNS, BGP hijacks, and rogue internal actors can all achieve MitM — and the 17-month window means any of them could have already done so undetectably.
  • Trivial key recovery eliminates attacker skill as a barrier. Unlike most CA compromises requiring HSM theft or sophisticated attacks, these keys are literally single-byte integers. A script kiddie with Python can forge a trusted certificate for any domain in seconds. The attacker cost is functionally zero once positioned.
  • Role multiplier: Go crypto/x509 is canonical to high-value infrastructure. Kubernetes (apiserver, kubelet, controller-manager — all Go), HashiCorp Vault, Docker/containerd, Terraform, etcd, Prometheus, and Argo CD all use crypto/x509 for TLS verification. A forged kube-apiserver certificate in a MitM position yields cluster takeover → fleet compromise. A forged Vault certificate yields secret exfiltration → domain/cloud credential theft. These are not edge cases — they represent the *primary* deployment pattern for Go. ≥50% of Go binary deployments occupy high-value roles by definition. The blast radius floor is HIGH.
  • Code-signing intermediates extend impact beyond TLS. Two of eight compromised intermediates (EM OV CS CA G3B/G3C) issue code-signing certificates. Forged code signatures could make malware appear legitimately signed, bypassing Windows SmartScreen, macOS Gatekeeper (if eMudhra roots are trusted), and enterprise allowlisting policies. This is a supply-chain-scale outcome.
  • Binary rebuild requirement amplifies remediation lag. Unlike browser or OS trust store updates that propagate automatically, every Go application binary must be individually rebuilt with Go ≥1.26.10 or ≥1.27.3. Container images with frozen Go binaries, embedded/IoT devices, and legacy deployments will remain vulnerable far longer than the OS trust store update cycle. Some container images have certificates expiring in July 2039.

Why not higher?

CRITICAL would require either confirmed active exploitation or a remotely exploitable code path without the MitM positioning requirement. The MitM prerequisite (AC:H) meaningfully reduces the reachable attack surface — most Go services communicate within VPCs over private networks where MitM is substantially harder. No certificates appeared in CT logs during the 17-month window, and no exploitation has been confirmed. Browser traffic — the largest surface — is already protected.

Why not lower?

MEDIUM would underweight the blast radius. Go crypto/x509 is not an optional library in a niche product — it is THE trust verification layer for the entire Go ecosystem, which dominates cloud-native infrastructure. Kubernetes alone represents millions of clusters. The key recovery is trivial (zero attacker cost), the exposure window was 17 months, and the code-signing compromise adds a supply-chain dimension. The role multiplier for Kubernetes, Vault, and container runtimes floors this at HIGH regardless of MitM friction.

06 · Verification

Crowdsourced verification payload.

Run this script on each target host (Linux/macOS) where Go applications are deployed. Execute as root or with sudo for full binary scanning: sudo bash check_cve_2026_111943.sh. No network access required — it checks local Go toolchain version, OS trust store status, and scans for Go binaries built with vulnerable toolchains.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-111943 — eMudhra compromised intermediate CA denylist check
# Checks: (1) Go toolchain version, (2) OS ca-certificates, (3) Go binary build versions
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -euo pipefail

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
vulnerable=0
checks_run=0

echo "=== CVE-2026-111943 Check: eMudhra Intermediate CA Denylist ==="
echo ""

# --- Check 1: Go toolchain version ---
echo "[Check 1] Go toolchain version"
if command -v go &>/dev/null; then
  GO_VERSION=$(go version | grep -oP 'go[0-9]+\.[0-9]+\.?[0-9]*')
  GO_MAJOR=$(echo "$GO_VERSION" | grep -oP '[0-9]+' | head -1)
  GO_MINOR=$(echo "$GO_VERSION" | grep -oP '[0-9]+' | sed -n '2p')
  GO_PATCH=$(echo "$GO_VERSION" | grep -oP '[0-9]+' | sed -n '3p')
  GO_PATCH=${GO_PATCH:-0}
  checks_run=$((checks_run + 1))
  if [[ "$GO_MINOR" -eq 26 && "$GO_PATCH" -ge 10 ]] || \
     [[ "$GO_MINOR" -eq 27 && "$GO_PATCH" -ge 3 ]] || \
     [[ "$GO_MINOR" -gt 27 ]]; then
    echo -e "  ${GREEN}PATCHED${NC}: $GO_VERSION (>= 1.26.10 or >= 1.27.3)"
  else
    echo -e "  ${RED}VULNERABLE${NC}: $GO_VERSION (needs >= 1.26.10 or >= 1.27.3)"
    vulnerable=1
  fi
else
  echo -e "  ${YELLOW}SKIPPED${NC}: go not found in PATH"
fi

echo ""

# --- Check 2: OS trust store — look for eMudhra intermediates ---
echo "[Check 2] OS trust store (eMudhra intermediate presence)"
# Known compromised intermediate CN fragments
EMUDHRA_PATTERNS=("EM DV TLS CA" "EM OV TLS CA" "EM EV TLS CA" "EM OV CS CA")
found_emudhra=0

if [[ -f /etc/ssl/certs/ca-certificates.crt ]]; then
  CERT_BUNDLE="/etc/ssl/certs/ca-certificates.crt"
elif [[ -f /etc/pki/tls/certs/ca-bundle.crt ]]; then
  CERT_BUNDLE="/etc/pki/tls/certs/ca-bundle.crt"
elif [[ -f /etc/ssl/cert.pem ]]; then
  CERT_BUNDLE="/etc/ssl/cert.pem"
else
  CERT_BUNDLE=""
fi

if [[ -n "$CERT_BUNDLE" ]]; then
  checks_run=$((checks_run + 1))
  for pattern in "${EMUDHRA_PATTERNS[@]}"; do
    if grep -qi "$pattern" "$CERT_BUNDLE" 2>/dev/null; then
      echo -e "  ${RED}VULNERABLE${NC}: Found '$pattern' in $CERT_BUNDLE"
      found_emudhra=1
      vulnerable=1
    fi
  done
  if [[ $found_emudhra -eq 0 ]]; then
    echo -e "  ${GREEN}PATCHED${NC}: No compromised eMudhra intermediates in $CERT_BUNDLE"
  fi
else
  echo -e "  ${YELLOW}SKIPPED${NC}: Could not locate system CA bundle"
fi

echo ""

# --- Check 3: Scan for Go binaries built with vulnerable versions ---
echo "[Check 3] Scanning for Go binaries built with vulnerable Go versions"
echo "  (scanning common paths — may take a moment)"
vuln_binaries=0
SCAN_PATHS=(/usr/local/bin /usr/bin /opt /srv /home)
for spath in "${SCAN_PATHS[@]}"; do
  [[ -d "$spath" ]] || continue
  while IFS= read -r -d '' binary; do
    # Extract Go build version from binary
    build_ver=$(strings "$binary" 2>/dev/null | grep -oP '^go1\.[0-9]+\.?[0-9]*$' | head -1 || true)
    if [[ -n "$build_ver" ]]; then
      b_minor=$(echo "$build_ver" | grep -oP '[0-9]+' | sed -n '2p')
      b_patch=$(echo "$build_ver" | grep -oP '[0-9]+' | sed -n '3p')
      b_patch=${b_patch:-0}
      if [[ "$b_minor" -eq 26 && "$b_patch" -lt 10 ]] || \
         [[ "$b_minor" -eq 27 && "$b_patch" -lt 3 ]] || \
         [[ "$b_minor" -lt 26 ]]; then
        echo -e "  ${RED}VULNERABLE${NC}: $binary (built with $build_ver)"
        vuln_binaries=$((vuln_binaries + 1))
        vulnerable=1
      fi
    fi
  done < <(find "$spath" -type f -executable -print0 2>/dev/null)
done
checks_run=$((checks_run + 1))
if [[ $vuln_binaries -eq 0 ]]; then
  echo -e "  ${GREEN}PATCHED${NC}: No vulnerable Go binaries found in scanned paths"
else
  echo -e "  ${RED}FOUND${NC}: $vuln_binaries Go binary(ies) built with vulnerable Go versions"
fi

echo ""
echo "========================================"
if [[ $checks_run -eq 0 ]]; then
  echo -e "Result: ${YELLOW}UNKNOWN${NC} — no checks could be performed"
  exit 2
elif [[ $vulnerable -gt 0 ]]; then
  echo -e "Result: ${RED}VULNERABLE${NC} — action required (see CVE-2026-111943)"
  exit 1
else
  echo -e "Result: ${GREEN}PATCHED${NC} — system appears protected"
  exit 0
fi