When a Valid TLS Chain Lies
The certificate was valid. The identity was not.
Publication detail | Value |
|---|---|
Category | PKI / TLS / applied cryptography |
Evidence current through | 26 October 2026 |
Estimated reading time | approximately 35 minutes at 200 words per minute |
Executive Summary
GHOSTTRUST LAB synthetic training evidence. The opening banking scenario and every GhostTrust name, certificate, key and transaction are fictional. They reproduce a failure class without using real compromised material.
Imagine that Meridian Bank uses a clearing service to decide whether a $48,750 transfer should be released. A separate query to the genuine comparison origin returns HOLD. In the simulated attack path, the bank is preconfigured to contact a synthetic gateway controlled by Mallory. Network position alone should not be enough: the bank's TLS client is supposed to reject a server that cannot prove its identity. Mallory instead recovers the private key of a trusted intermediate certificate authority, signs a new certificate for the clearing hostname, and presents it to a stale client. The client reports a valid TLS chain and accepts the gateway-generated APPROVED response. GhostTrust assumes this attacker position; it does not demonstrate acquiring it or transparently intercepting the genuine origin.
REAL INCIDENT confirmed public evidence. The public record establishes recoverable eMudhra intermediate CA keys, the affected certificate classes, the root-program response and the limits described below. It does not establish a real bank attack.
GhostTrust demonstrates the cryptographic and trust-policy portion of that attack: weak-key recovery, unauthorized issuance, stale-chain acceptance and consumption of attacker-controlled data. It is also the central risk created by the October 2026 eMudhra incident: eight intermediate CA private keys were recoverable from public certificate material. Chrome's incident response classified six as TLS-issuing intermediates and two as Code Signing intermediates. The eMudhra root private keys were not compromised. The root failure carries no CVE of its own; it was a certificate-authority key-generation failure, not a flaw in TLS, P-384, or any cryptographic library, and not evidence that ordinary elliptic-curve keys can be guessed. The CVEs that do exist, Firefox’s CVE-2026-113470 and Go’s CVE-2026-111943, track client software that kept trusting the compromised certificates until updated, not a cryptographic break.
It was a key-generation failure that reduced supposedly strong private values to a tiny search space. Chrome Root Program response eMudhra incident update
The real attack also has hard prerequisites. Mallory must be in an active adversary-in-the-middle position, and the victim client must still accept a chain through an affected authority. Possession of an intermediate key does not passively decrypt recorded TLS sessions, recover historical plaintext, or place an attacker on the network path. Chrome reported that its CRLSet block and Certificate Transparency enforcement protected default Chrome before any certificate chaining to the six TLS intermediates had appeared in CT. The difficult tail was and remains in incidents like this non-browser software with stale or private trust bundles. Chrome Root Program response public client-remediation tracker
I reviewed the public Mozilla incident record, the Chrome and Mozilla root-program discussion, the published certificate inventory, eMudhra's update current on 26 October, the GhostTrust target and helper source, and a supplied end-to-end lab transcript. I did not recover or use any real eMudhra private key, test a public service, or reproduce eMudhra's infrastructure. The runtime claims below are limited to the supplied, verified GhostTrust execution record.
At a glance
Question | Evidence-backed answer |
|---|---|
Incident type | Recoverable intermediate CA private keys caused by catastrophically small P-384 private scalars |
Affected material | Six TLS-issuing and two Code Signing intermediate CA keys |
Root private keys | Not part of the reported compromise |
TLS impersonation prerequisite | An active adversary-in-the-middle position plus a client that still accepts an affected path |
Passive or historical decryption | Not enabled by possession of an intermediate CA signing key |
Malicious pre-disclosure exploitation | No public evidence identified; absence of evidence is not proof that no unseen attempt occurred |
GhostTrust | A synthetic, controlled training implementation not eMudhra infrastructure and not a CVE |
Chrome's response provides the six-TLS/two-Code-Signing classification and its CT and CRLSet findings. eMudhra says it found no evidence that the weak keys were recovered or exploited before disclosure, while its full root-cause analysis remained pending on 26 October. Chrome Root Program response eMudhra incident statement
Background
The certificate in the middle
A browser or application rarely receives a leaf certificate signed directly by a root CA. More often, trust is delegated:
trusted root CA
└── intermediate CA
└── server certificate for api.example
The root is the long-lived trust anchor. The intermediate performs day-to-day issuance. If an intermediate's signing key is recovered, an attacker can create new leaf certificates that appear to descend from that trusted hierarchy. TLS can still negotiate modern ciphers and encrypt every byte; the failed property is authentication. The client has established a confidential channel to the wrong endpoint.
For an elliptic-curve key, the certificate publishes a public point Q, while the private scalar d should remain secret:
Q = dG
Here, G is the curve's standard generator. Recovering a properly generated P-384 scalar from Q is infeasible with current methods. That protection disappears when d comes from a tiny candidate set: derive dG for each candidate and compare it with the public point already present in the certificate. The algorithm has not failed; the private value never had the expected entropy.
How the incident surfaced
The public reporter identifies only as Wayne. According to Wayne's Bugzilla timeline, a test against a CCADB certificate corpus first detected the broken EC keys at 16:27 UTC on 17 October 2026. At 18:05 UTC, Wayne sent the report and signed attestations to Apple, Chrome, Microsoft, Mozilla and eMudhra. Wayne later explained that Google's open-source paranoid_crypto found the weakness “out of the box”; CCADB had initially been intended as a quick corpus test. Wayne's discovery timeline Wayne's discovery explanation
The attestations mattered because they did more than point at suspicious public keys. Wayne signed a fixed message with each recovered intermediate private key, and the signatures could be checked against the corresponding public certificates. That establishes control of each signing key without publishing the private keys themselves. public proof description
Incident timeline
Date and time (UTC) | Event |
|---|---|
30 April 2025 | eMudhra says the eight intermediates were created during a key-generation ceremony. |
17 October 2026, 16:27 | Wayne's CCADB corpus test detects the weak EC keys. |
17 October 2026, 18:05 | Wayne reports the issue and sends per-key attestations to the root programs and eMudhra. |
17 October 2026, 19:45 | Chrome says it completed corroboration and landed an SPKI-based CRLSet block for the six TLS-issuing keys. |
18 October 2026, by 09:38 | The eight intermediate certificates are recorded as revoked for CA compromise. |
20 October 2026 | Mozilla publicly describes its response and publishes an NSS trust-store update removing the signing root for downstream users. |
26 October 2026 | eMudhra confirms a script error produced weak keys; its full root-cause analysis remains pending. |
Sources: Mozilla Bugzilla incident, Mozilla and Chrome root-program discussion, and eMudhra's incident statement.
What is known and what is not
The published inventory identifies eight affected certificates using P-384 keys. Chrome's response separates them into six TLS-issuing and two Code Signing intermediates; the Code Signing constraints did not permit Chrome to construct a TLS path through those two. The affected intermediates were created on 30 April 2025. eMudhra says a script error during a key wrap/unwrap step produced a second, weak set of keys alongside the intended strong keys, and the weak set was published. Chrome Root Program response eMudhra's 26 October update
That is the current boundary of the confirmed root cause. As of 26 October, eMudhra says the exact mechanism is still under investigation and promises a full analysis through the CCADB process. Speculation about test vectors, reference files or HSM behavior should not be presented as settled fact. The confirmed failure is weak published intermediate keys; the precise code path that produced them remains pending.
In Bugzilla comment 43, eMudhra also stated that it had decided to exit the public TLS business. That is eMudhra's own incident-response statement; it is not a regulator sanction, and it does not mean customer migration was complete on 26 October. The same comment says the full report was still being prepared. eMudhra statement in Bugzilla comment 43
eMudhra says it had not issued publicly trusted end-entity certificates from the eight affected CAs before disclosure. Researchers later created certificates with recovered keys as proof and research activity; those post-disclosure certificates demonstrate that the signing capability was real, not that malicious exploitation occurred before disclosure. eMudhra incident statement Mozilla Bugzilla discussion
Vulnerability Details
From a public certificate to a signing capability
A certificate is designed to publish its subject, issuer, validity period, permitted uses and public key. That normally reveals nothing practical about the private scalar. The eMudhra intermediates broke that assumption because the scalar space was extremely small. Anyone who obtained the public certificates could test candidate scalars offline, compare each derived public point with the certificate's public point, and stop on a match.
Once recovered, the intermediate key carries the authority encoded in the certificate. For a TLS-capable intermediate, Mallory can generate a new leaf key, construct a certificate naming a service she does not own, and sign it with the recovered intermediate key. The forged leaf is not self-signed; it forms a cryptographically valid chain to the same root that a stale client already trusts.
The following is a possible real-world abuse path, not the literal GhostTrust service topology:
The diagram contains two different failures that must coincide. The CA failure gives Mallory a signing capability. The relying-party failure leaves the affected trust path usable. Neither one places Mallory on the network path, so DNS manipulation, a malicious proxy, BGP interference, gateway control or some equivalent active position is still required.
Why a green lock can be the wrong answer
Certificate validation answers a specific question: can the presented leaf be linked, under current policy, to an accepted trust anchor for the requested hostname? It does not independently know whether an intermediate key was generated safely. If the signature is mathematically correct and the affected intermediate is still accepted, the client can return “verification OK” even though an unauthorized party created the leaf.
This distinction explains the urgency of root-program blocklists. Chrome says it blocked the SPKI hashes of all six TLS-issuing keys, covering both eMudhra-issued intermediates and Sectigo cross-certificates that shared those keys. Mozilla used OneCRL and then removed the relevant root from NSS for downstream consumers that do not receive Firefox's live protections. Chrome Root Program response Mozilla response
The browser response and the client long tail
Chrome reported an important negative finding: before its 17 October block, no TLS certificates chaining to the six intermediates had been logged to Certificate Transparency. Because default Chrome requires CT for roots in the Chrome Root Store, such an unlogged forged certificate would have been rejected. That substantially narrows the demonstrated browser impact; it does not prove that every non-browser client was safe.
Command-line tools, embedded devices, application containers, language runtimes and applications can carry their own CA bundle, omit CT enforcement, or handle revocation differently. Updating a desktop browser does not update a CA file baked into an old image. The public remediation tracker documents this distributed patch problem across operating systems, bundles, runtimes and libraries. client-remediation tracker
Exploitability Analysis
What the evidence establishes
The public attestations establish recovery of the eight intermediate signing keys. The inventory and root-program responses establish that six keys were associated with TLS-issuing intermediates and two with Code Signing intermediates. This is a real signing primitive, not merely a malformed-certificate observation.
Impact versus evidence
Statement | Classification | What the record supports |
|---|---|---|
Eight intermediate signing keys were recoverable | Confirmed fact | Wayne's signed attestations and independent Mozilla recovery established control of the keys |
Six keys could issue TLS chains; two were Code Signing constrained | Confirmed fact | Chrome's root-program response distinguishes the two certificate classes |
An unauthorized certificate can support TLS service impersonation | Realistic conditional impact | The attacker must also control the network path, choose a valid hostname and reach a client that still accepts the affected chain |
GhostTrust's stale connector accepted an attacker-controlled APPROVED response while the separately queried genuine origin returned HOLD | Confirmed lab-only result | The supplied transcript records the synthetic legacy connector accepting APPROVED while the genuine origin returned HOLD |
The weak keys were maliciously exploited before disclosure | Not demonstrated | eMudhra reports no evidence of pre-disclosure recovery or exploitation; the public record does not prove an unseen attempt was impossible |
Root keys, P-384 or TLS itself were broken | Non-claim | The reported compromise concerned intermediate keys generated with tiny scalar values, not a cryptanalytic break of the curve or protocol |
Recorded TLS sessions can now be passively decrypted | Non-claim | An intermediate CA signing key enables certificate issuance; it is not the session secret or a server's historical leaf private key |
For TLS impersonation, Mallory still needs all of the following:
A recoverable TLS intermediate key. The six TLS-capable keys satisfy this condition; Code Signing constraints do not automatically become TLS authority.
An active network position. Mallory must cause Alice's connection to reach Mallory's endpoint or otherwise intercept and terminate it.
A client that still accepts the affected path. A current browser with the emergency block and CT enforcement is a different target from a stale service using a bundled CA file.
A matching leaf certificate. The certificate must satisfy hostname and relevant usage checks.
A useful application exchange. Mallory can only read or modify traffic that the intercepted client sends through the impersonated endpoint.
Under those conditions, the plausible impact includes service impersonation, credential capture, malicious update or API responses, and modification of application data in transit. The concrete GhostTrust result is narrower: one synthetic bank connector accepts an attacker-controlled settlement decision that differs from the separate genuine-origin response.
What this does not prove
This incident should not be described as passive decryption. Eve, a passive observer with packet captures, does not gain historical plaintext simply because an intermediate signing key becomes known. Modern ephemeral TLS key exchange is not reversed by possession of a CA signing key.
It also does not prove:
compromise of an eMudhra root private key;
compromise of eMudhra infrastructure or customer data;
prior malicious exploitation of the weak keys;
universal exposure of browsers after the emergency blocks;
a flaw in the P-384 curve, OpenSSL or TLS itself;
that every application trusting an eMudhra root would accept every affected chain; or
that certificate possession alone supplies DNS, routing or proxy control.
eMudhra says the affected intermediates had not issued publicly trusted end-entity certificates before disclosure and that it found no compromise of infrastructure or customer data. Chrome's CT review found no pre-block entries chaining to the six TLS intermediates. Those are meaningful negative findings, while not being a proof about unlogged, non-CT clients. eMudhra's 26 October update Chrome Root Program response
Detection: find trust that outlived the incident
Defenders should start with the exact affected-certificate fingerprints and SPKI values in the published JSON inventory, then answer where those chains can still validate.
Useful checks include:
inventory OS, runtime, application, container, proxy and appliance trust stores separately;
identify images or binaries that embed their own CA bundle rather than using the host store;
compare bundle versions with the relevant vendor's patched release;
test whether revocation is checked for intermediates, not only leaf certificates;
inspect outbound TLS telemetry for affected issuer names, certificate fingerprints or SPKI hashes;
search certificate inventories and CT monitoring for unexpected leaves chaining to the affected keys, while remembering that absence from CT does not clear non-CT traffic; and
verify that emergency distrust reaches long-lived workloads after rebuild and redeployment, not merely the build host.
The question is not just “did we patch Chrome?” It is “which TLS verifier made this connection, and which trust state did that verifier actually load?”
Lab-value clarification: The private scalar 173 is an intentionally selected fictional value used only in GhostTrust. It is not an eMudhra private-key value. The real incident involved eight weak intermediate CA keys, six TLS-issuing and two Code Signing whose private scalars were reportedly below 256; the lab reproduces this vulnerability class without using real compromised key material.
Proof of Concept
GHOSTTRUST LAB synthetic training evidence. This walkthrough uses only the fictional GhostTrust target and the supplied Kali desktop. It does not recover or distribute a real eMudhra key, contact eMudhra, or test a real bank.
Screenshot provenance. Every image in this walkthrough is a curated lab-manual illustration captured from the synthetic GhostTrust environment. The screenshots are not raw evidence from the public eMudhra incident and should not be interpreted as such.
Overview
The 2026 eMudhra certificate incident involved intermediate CA private keys whose values had catastrophically low entropy. Public reporting described P-384 private values small enough to recover by testing only the candidate range 1..255. Control of a TLS-issuing intermediate key whose constraints permit server authentication can allow an attacker to issue unauthorized TLS certificates for sites they do not control.
This lab safely recreates the same vulnerability class and exploitation mechanism with fictional certificates, domains, organizations, and banking records. The target is one standalone container, while you work from the separately provided Kali GUI.
Task
Investigate Meridian Bank’s settlement-verification path. Recover the weak private scalar belonging to the supplied fictional intermediate CA certificate, issue a certificate for the lab clearing hostname, demonstrate that the legacy connector accepts a response from the simulated attacker endpoint, and verify that the patched connector rejects the same certificate chain.
Objective
By completing the exercise, you will demonstrate:
recovery of an extremely low-entropy P-384 private scalar;
unauthorized leaf-certificate issuance from a compromised intermediate;
TLS impersonation in a simulated, preconfigured attacker position;
acceptance of attacker-controlled business data despite successful TLS validation; and
mitigation through an updated trust policy.
How the simulated scenario works
The standalone target contains several logical services on one IP. The lab’s configured routing places a synthetic clearing gateway in the bank application’s clearing path. After the student-generated certificate is installed, that gateway presents the unauthorized chain and returns its own controlled settlement response.
The genuine origin is a separate comparison endpoint. The gateway does not transparently fetch, decrypt, modify, or re-encrypt the genuine origin’s traffic. The exercise proves unauthorized certificate issuance, acceptance of an impersonating endpoint, and the security difference between stale and patched trust policies. It does not independently create or demonstrate a real network interception position.
Lab Scenario
The diagram below shows the complete GhostTrust workflow. The student first recovers the deliberately weak private scalar associated with the fictional Atlas intermediate CA. That recovered signing key is then used to issue an unauthorized TLS certificate for clearing.meridian-bank.local, which is installed on the simulated attacker gateway.
The Meridian Bank application is already configured to contact this gateway for settlement verification. Its legacy connector accepts the unauthorized certificate because the stale trust bundle still contains the Atlas root. The gateway can therefore return attacker-controlled settlement data through a TLS connection that validates successfully. The patched connector removes the Atlas authority from its trust policy and rejects the same certificate chain.
The genuine clearing origin is provided only as a comparison endpoint. The simulated gateway does not fetch, intercept, decrypt, modify, relay, or re-encrypt traffic from the genuine origin.
Diagram-label clarification. The tested standalone lab uses clearing-origin.local for the separate genuine comparison endpoint, and the simulated gateway returns the decision APPROVED. The labels clearing.meridian-bank.local and SETTLED in this supplied overview graphic are schematic; the commands, captured outputs and written walkthrough below are authoritative.
Solution
Step 1: Start from the provided Kali GUI
Use the Kali desktop supplied by the lab platform. Do not SSH into Kali. The target names have already been mapped to the single target IP, so do not edit /etc/hosts.
Open a terminal and confirm the four names resolve to the same target address:
getent hosts meridian-bank.local
getent hosts clearing.meridian-bank.local
getent hosts clearing-origin.local
getent hosts gateway-status.local
Using one IP is intentional. The standalone target separates its logical services through HTTP host names and TLS Server Name Indication (SNI).
Step 2: Download the student evidence kit
Create a working directory and retrieve the kit directly from the target:
mkdir -p ~/ghosttrust-lab
cd ~/ghosttrust-lab
curl -fsS http://gateway-status.local:8080/lab/lab-kit.tar.gz | tar -xz
find . -maxdepth 2 -type f | sort
lab-kit.tar.gz is the downloadable student-material bundle for the fictional GhostTrust exercise. The target serves it over port 8080 so every student receives the same public evidence, trust policies, and restricted helper scripts. The archive is not a running service and downloading or extracting it does not exploit the target.
The archive contains:
README.txt summarizes the fictional endpoints, starting workflow, and safety boundary.
evidence/atlas-root.crt the fictional Atlas root CA certificate used to understand the affected trust hierarchy.
evidence/atlas-weak-intermediate.crt the public P-384 intermediate CA certificate audited in the lab. It contains the public key, not the private scalar.
trust/legacy-trust.pem the stale trust bundle containing both the fictional Meridian and Atlas roots. After the controlled certificate installation, this bundle accepts the student-generated Atlas chain.
trust/meridian-root.crt the fictional Meridian root used by curl to authenticate the genuine clearing-origin.local endpoint.
trust/patched-trust.pem the updated trust bundle containing only the Meridian root. Atlas has been removed, so the same student-generated chain is rejected.
recover_weak_key.py an offline helper that tests the deliberately restricted scalar range 1..255 against the public point in atlas-weak-intermediate.crt. When it finds the matching lab value, it creates recovered-intermediate.key locally.
forge_lab_certificate.py a restricted helper hard-coded to issue only for clearing.meridian-bank.local. It creates artifacts/forged-leaf.pem, artifacts/forged-fullchain.pem, and artifacts/forged-key.pem, then sends the chain and leaf key to the lab-only /install endpoint.
The following files are generated while the student performs the exercise; they are not shipped inside the archive:
recovered-intermediate.key the recovered fictional intermediate private key; and
artifacts/forged-leaf.pem, artifacts/forged-fullchain.pem, and artifacts/forged-key.pem the fictional leaf certificate, complete presented chain, and matching leaf private key.
The kit contains no real CA material, real compromised private key, packet capture, eMudhra certificate, or real bank data. It is lab scaffolding, not the vulnerability itself. The result is demonstrated only after the controlled recovery, issuance, installation, legacy-validation, and patched-rejection steps are completed inside GhostTrust.
Confirm the required Python library is available:
python3 -c "import cryptography; print(cryptography.__version__)"
This one-line Python command only imports the required library and prints its installed version. It is a dependency check; it does not contact or exploit the target.
Step 3: Inspect the Meridian Bank application
Open Firefox and visit:
http://meridian-bank.local/
The portal shows a pending transfer with reference MB-20481, beneficiary ACME-SUPPLIES, and amount $48,750.00. It also reveals that the clearing connector uses a legacy trust bundle whose last refresh was 28 days ago.
The browser-facing portal uses HTTP in this standalone package so it does not require changes to the platform’s Kali trust store. The security exercise concerns the bank application’s authenticated outbound TLS connection to the clearing service.
Step 4: Enumerate the standalone target
Scan the relevant ports:
nmap -Pn -sT --version-light -p 80,443,8080 meridian-bank.local
The ports represent:
80/tcp bank portal and application API;
443/tcp SNI-routed bank, clearing gateway, and genuine origin endpoints; and
8080/tcp lab-kit and target-status service.
Check the clean gateway state:
curl -sS http://gateway-status.local:8080/status | jq .
forged_material_present should be false and certificate_profile should be untrusted-bootstrap.
Step 5: Establish the clean TLS behavior
Ask the bank’s legacy connector to validate the transfer:
curl -sS "http://meridian-bank.local/api/transfer-preview?mode=legacy" | jq .
The gateway is in the application’s configured path, but its bootstrap certificate cannot chain to a root in the legacy trust bundle. Network position alone is therefore insufficient.
Step 6: Inspect the weak intermediate
Inspect the fictional certificate identity:
openssl x509 \
-in evidence/atlas-weak-intermediate.crt \
-noout -subject -issuer -serial -dates
Inspect its key type and CA extensions:
openssl x509 \
-in evidence/atlas-weak-intermediate.crt \
-noout -text | \
grep -E "Public Key Algorithm|ASN1 OID|CA:TRUE|Key Usage"
The certificate uses P-384 (secp384r1) and has CA:TRUE. For an elliptic-curve key, the public point is Q = dG, where d is the private scalar. A correctly generated P-384 scalar has an enormous candidate space. In this exercise, d is known to be between 1 and 255, making direct comparison practical.
Step 7: Recover the private scalar
Run the supplied audit helper:
How the recovery script works
recover_weak_key.py reads the public P-384 point from the supplied intermediate certificate. It derives a public point for every candidate scalar from 1 through 255 and compares each result with the certificate’s public key. When the points match, the corresponding scalar is written locally as recovered-intermediate.key.
This operation is performed entirely offline and does not modify any target service.
python3 recover_weak_key.py
What recover_weak_key.py does and why
This is a supplied cryptographic audit helper, not a programming exercise. It works entirely offline against the fictional certificate:
It opens evidence/atlas-weak-intermediate.crt and extracts the P-384 public point Q. A certificate contains this public value; it does not contain the private scalar.
It tests the deliberately restricted lab range 1..255. In Python, range(1, 256) includes 1 and stops before 256, so exactly 255 candidates are tested.
For each candidate scalar d, the cryptography library derives the corresponding public point dG on the secp384r1 curve.
It compares that candidate point with Q. An exact coordinate match means the candidate belongs to the certificate’s public key.
When candidate 173 matches, the helper serializes it as an unencrypted PKCS#8 PEM file named recovered-intermediate.key and restricts the file to mode 0600. If no candidate matches, the script exits without producing a key.
The recovered intermediate key is needed for the next step because it supplies the fictional CA signing authority used to issue the unauthorized leaf certificate. This works only because the exercise deliberately limits the search to 255 known candidates. It is not extraction of a secret field from the certificate, an ECDSA nonce attack, a general elliptic-curve attack, or a break of P-384.
Confirm that the recovered key matches the certificate public key:
openssl pkey -in recovered-intermediate.key -pubout -outform DER | sha256sum
openssl x509 -in evidence/atlas-weak-intermediate.crt -pubkey -noout | \
openssl pkey -pubin -outform DER | sha256sum
The first command derives the public key from recovered-intermediate.key. The second extracts the public key embedded in the certificate. Both are normalized to DER before SHA-256 hashing. Matching hashes show that the two public keys are byte-for-byte identical, confirming that the recovered private key corresponds to the certificate without displaying the private scalar itself.
Step 8: Issue, inspect, and install the lab certificate
The kit was extracted directly into ~/ghosttrust-lab, so the forging helper is located at ~/ghosttrust-lab/forge_lab_certificate.py. Run it from the extracted kit directory:
cd ~/ghosttrust-lab
python3 forge_lab_certificate.py
How certificate forging and installation work
forge_lab_certificate.py generates a new leaf key pair and constructs a TLS server certificate restricted to clearing.meridian-bank.local. It signs that certificate using the recovered fictional intermediate key.
The helper creates the leaf certificate, the presented certificate chain, and the matching leaf private key. It then uploads the full chain and leaf key to the lab-only /install endpoint. After installation, the simulated gateway can present the unauthorized chain during a TLS handshake for the clearing hostname.
What forge_lab_certificate.py does and why
This second supplied helper demonstrates what possession of the fictional intermediate signing key permits. Students run it as provided; they do not need to write or modify Python code.
The helper loads the Atlas intermediate certificate and recovered-intermediate.key, generates a fresh P-384 private key for the server, and builds a 30-day leaf certificate restricted to clearing.meridian-bank.local. The leaf is marked CA:FALSE, contains that exact DNS Subject Alternative Name, includes TLS server-authentication usage, receives a random serial number, and is signed by the recovered intermediate key using SHA-384.
It then writes the leaf certificate, the presented leaf-plus-intermediate chain, and the new leaf private key beneath artifacts/. Finally, it sends the chain and matching leaf key to the lab-only /install endpoint so the disposable target can present them on the next TLS handshake for the clearing SNI hostname.
The /install endpoint is exercise orchestration not the real vulnerability. It does not recover a key, create a network interception position, contact the genuine origin, or proxy its traffic. Its only purpose is to activate the student-generated identity inside this controlled target so the legacy and patched verification policies can be compared.
The certificate construction happens on Kali. On the target, the installation endpoint checks that the uploaded certificate and private key can be loaded as a pair and that the certificate’s DNS SAN is exactly clearing.meridian-bank.local. It then stores that material in the lab’s temporary state. For a new TLS connection using that SNI hostname, the clearing service selects the installed certificate instead of the bootstrap certificate. The /install endpoint does not decide whether the chain is trusted; that decision is made later by the bank connector using either the legacy or patched CA bundle.
The helper is hard-coded to issue only for clearing.meridian-bank.local. It creates these runtime files beneath the extracted kit:
artifacts/forged-leaf.pem - the generated server certificate;
artifacts/forged-fullchain.pem - the leaf followed by the fictional Atlas intermediate; and
artifacts/forged-key.pem - the matching leaf private key, stored with mode 0600.
Inspect the generated leaf certificate before testing it:
openssl x509 \
-in artifacts/forged-leaf.pem \
-noout -subject -issuer -serial -dates -ext subjectAltName
Confirm that the subject identifies the fictional clearing service, the issuer is Atlas DV TLS CA - G3B, and the Subject Alternative Name contains DNS:clearing.meridian-bank.local.
The helper defines BASE = Path(__file__).resolve().parent, so it resolves every path from the directory containing the script not from an arbitrary shell working directory. It reads evidence/atlas-weak-intermediate.crt and recovered-intermediate.key beside the script, creates artifacts/ beside the script, and then POSTs the full chain and leaf key to the lab-only http://gateway-status.local:8080/install endpoint.
Standalone path warning: Do not use student-kit/ or drop/ in this student workflow. Those names belong to the source-delivery layout and the older multi-container range. The archive downloaded from the standalone target extracts forge_lab_certificate.py, recover_weak_key.py, evidence/, and trust/ directly into ~/ghosttrust-lab.
Verify the clearing endpoint through the legacy trust bundle:
openssl s_client \
-connect clearing.meridian-bank.local:443 \
-servername clearing.meridian-bank.local \
-CAfile trust/legacy-trust.pem \
-verify_return_error </dev/null 2>/dev/null | \
grep -E "subject=|issuer=|Verification"
Verification: OK confirms that the unauthorized leaf is valid according to the stale trust policy.
Why the legacy and patched results differ
Both connectors receive the same server name, forged leaf certificate, intermediate certificate, and gateway-controlled response. The difference is their trust policy.
The legacy bundle still contains the fictional Atlas root, allowing the forged leaf to build a trusted path through the compromised intermediate. TLS validation succeeds, and the application consumes the gateway-controlled business response. The patched bundle contains only the Meridian root. Because the Atlas chain can no longer reach a trusted root, certificate validation fails and the response is blocked.
The genuine clearing origin remains a separate comparison endpoint and is authenticated using the fictional Meridian root.
Diagram-label clarification. In the captured lab response, the legacy connector accepts the gateway-controlled decision APPROVED; SETTLED in this supplied conceptual graphic is shorthand for the attacker-controlled settlement outcome.
Step 9: Compare the genuine and attacker-controlled responses
Query the genuine clearing origin using its fictional Meridian root:
curl -sS --cacert trust/meridian-root.crt \
"https://clearing-origin.local/v1/validate?reference=MB-20481&beneficiary=ACME-SUPPLIES&amount=48750.00" | jq .
The genuine origin returns beneficiary ACME-SUPPLIES, decision HOLD, fraud score 87, and intercepted: false.
Now repeat the bank’s legacy verification:
curl -sS "http://meridian-bank.local/api/transfer-preview?mode=legacy" | jq .
The response accepted from the simulated gateway contains beneficiary HARBOR-CONSULTING-8821, decision APPROVED, fraud score 3, and intercepted: true. These values differ from the independently queried genuine origin. The intercepted field is an explicit lab marker; it is not evidence that the gateway transparently proxied and modified the genuine origin response.
Record the first flag:
LAB{a_valid_chain_can_still_be_untrustworthy}
TLS encryption still operated. The failure was authentication: the reconstructed intermediate key allowed the simulated gateway to present a chain accepted by the stale client, after which the client consumed content supplied by that impersonating endpoint.
Step 10: Verify the patched trust policy
Send the same request through the patched connector:
curl -sS "http://meridian-bank.local/api/transfer-preview?mode=patched" | jq .
The patched trust bundle excludes the fictional Atlas authority, so the certificate path fails. Record the second flag:
LAB{every_tls_client_needs_revocation_updates}
Step 11: Review the audit trail
curl -sS http://meridian-bank.local/api/audit | jq .
The events show the clean blocked request, the accepted legacy request after certificate installation, and the patched rejection. The same events can be viewed from the portal.
Step 12: Connect the lab to real remediation work
The real incident required action in more places than browsers. An application might verify certificates through its operating system, a language runtime, a bundled CA file, a container base image, a proxy, an SDK, or custom code. Updating one verifier does not update all the others.
A defensible response should include:
Distrust the affected intermediate keys or issuing hierarchy in every active verification path, using the narrowest reliable control available.
Update shared trust stores, language and runtime CA bundles, container base images, VPN clients, proxies, API clients, and embedded systems.
Reload, restart, rebuild, or redeploy applications so the new policy is actually active.
Test the application's real TLS path; a successful browser or unrelated curl test does not prove that another verifier is protected.
Monitor Certificate Transparency and other available issuance telemetry for unauthorized certificates.
Replace affected certificates and keys where required, and investigate whether interception occurred.
Never work around new certificate errors by disabling verification.
Summary
You enumerated one standalone target image containing several realistic logical services. You retrieved only public evidence, recovered a deliberately weak P-384 intermediate private scalar, issued a lab-restricted clearing certificate, and proved that a stale application verifier accepted it.
The legacy path consumed an attacker-controlled banking decision even though TLS verification succeeded. The patched path rejected the same certificate after the affected authority was removed from its trust policy. The lab does not implement transparent interception of the genuine origin; it demonstrates acceptance of an impersonating endpoint under a stale trust policy. This shows why CA-key compromise response must reach every browser, operating system, language runtime, application bundle, container image, proxy, and embedded verifier that authenticates TLS endpoints.
References
Remediation
For relying parties: distrust must reach the process that verifies TLS
Revocation is useful only when the verifier that makes the connection actually obtains and enforces it. A response plan therefore has to follow the trust decision into every application, not stop at the browser or operating-system update.
Apply vendor emergency updates and rebuild workloads with current trust bundles.
Block affected SPKI hashes where supported. Because an SPKI block follows the key, it also covers cross-signed certificates that reuse that key the property Chrome relied on in its CRLSet response.
Verify that revocation processing checks intermediate CAs, not only leaf certificates, and understand whether the application fails closed when revocation data is unavailable.
Inventory independent and bundled stores in containers, language runtimes, appliances, proxies and long-lived processes; a host update does not automatically replace them.
Remove the affected root only where a narrower block is unavailable and the resulting availability impact has been assessed.
Enforce Certificate Transparency for public WebPKI use where the client ecosystem supports it.
Retest the exact application connection after deployment. A successful browser test on the same machine does not prove that the application loaded the same trust state.
Chrome's SPKI block and Mozilla's OneCRL response illustrate fast centralized controls. Their root-store changes addressed downstream consumers that did not receive those live blocklists. Chrome and Mozilla response thread
For certificate authorities: verify what was generated, not what the ceremony expected
The key-generation process needs controls that survive script and wrap/unwrap mistakes:
validate every generated public key for known weak-key classes before certificate issuance and publication;
independently verify that the public key certified is the key pair intended by the ceremony;
test wrap/unwrap and backup/restore steps as security-critical code paths;
require two-person review and durable audit evidence for deviations from the approved ceremony procedure;
continuously scan all disclosed CA certificates, not only roots, with tools such as paranoid_crypto or an actively maintained equivalent;
compare CRL and OCSP signing behavior with the certified keys; and
rehearse emergency intermediate distrust across root programs and downstream trust-store consumers.
These are remediation principles, not a claim that eMudhra has completed them. As of 26 October, eMudhra says its full root-cause analysis and independent review are still pending. eMudhra incident statement
Regression tests for GhostTrust
For the training target, the meaningful regression sequence is:
bootstrap certificate is rejected;
scalar recovery matches the fictional intermediate public key;
the legacy bundle accepts the forged lab chain;
the genuine and attacker-generated business responses differ;
the patched bundle rejects the same chain; and
reset removes the forged material and clears state.
The lab should keep the exact-SAN restriction on /install and its fictional trust hierarchy. Expanding that endpoint would not improve fidelity; it would only broaden the training tool beyond its stated safety boundary.
Summary
The eMudhra incident was a failure of intermediate CA key generation, not a break in TLS or elliptic-curve cryptography. Wayne's publicly documented CCADB scan found recoverable keys on 17 October 2026; signed attestations established control, root programs reacted quickly, and eMudhra revoked the eight intermediates. Chrome classified six as TLS-issuing and two as Code Signing, while confirming that the root private keys were not the compromised material. eMudhra now attributes the weak published keys to a script error around a wrap/unwrap step, but its exact root-cause analysis remains pending as of 26 October.
The potential TLS impact is serious but conditional: Mallory needs both an active network position and a client that still accepts the affected chain. That combination can turn a cryptographically valid connection into authenticated communication with the wrong endpoint. It cannot retroactively decrypt captured sessions, and the evidence does not establish malicious exploitation before disclosure.
GhostTrust makes that narrow mechanism visible with fictional material. It recovers synthetic scalar 173, signs a leaf for a fictional clearing hostname, shows Verification: OK under a stale bundle, records acceptance of a different attacker-controlled settlement decision, and then shows the patched client rejecting the same chain. The most important operational lesson is simple: encryption can remain mathematically sound while authentication fails because the client's trust state is stale. A root-program response protects only the clients that receive and enforce it. Incident response is complete only after the exact verifier making the real application connection has loaded a trust policy that rejects the compromised authority.
References
