EresusSecurity
Back to Research
Threat Intelligence

eMudhra Intermediate CA Compromise: Weak P-384 Keys and the Trust-Store Long Tail

Yiğit İbrahim SağlamOffensive Security Specialist
October 22, 2026
22 min read
Incident AnalysisPublic Key InfrastructureSource: eMudhra incident site, Mozilla bug 2083449, and Chrome / Mozilla trust decisionsSource date: 2026-10-20

Short answer: Eight eMudhra intermediate CA certificates were issued with P-384 private keys whose numeric value was below 256. That reduces key recovery from a hard discrete-logarithm problem to generating the first 255 P-384 keys and comparing public points. Six of the intermediates could issue TLS certificates and two could issue code-signing certificates. Chrome and Firefox blocked them on 17 October 2026. eMudhra's incident page says Apple followed on 19 October and Microsoft on 20 October. The durable fix is not a runtime patch. Every trust store that validates certificates must be updated, including the ones that do not update themselves: appliances, bundled Java keystores, old container images, custom PKI clients, and mTLS peers.

Item Detail
CA eMudhra (India), Global TLS and code-signing hierarchies
Scope 8 unique intermediates: 6 TLS, 2 code signing, per the incident JSON (16 entries; each intermediate appears under an eMudhra root and under Sectigo's AAA Certificate Services). eMudhra's status page says "eight (out of several)" Global TLS intermediates; that conflicts with the JSON split and is unresolved
Key type P-384 (secp384r1), 384-bit public keys
Defect Private scalar numeric value below 256, not "256-bit key"
Recovery cost At most 255 candidate keys; effectively instantaneous
Revocation reason ca_compromise
Browser block Chrome and Firefox, 17 October 2026
Root removal Chrome scheduled 27 October 2026 (PDT); Mozilla NSS 3.131.1 (20 October 2026) removes trust in emSign ECC Root CA - G3 (Bugzilla 2084101), per the NSS release announcement
Related CVE CVE-2026-111943 / GO-2026-6809 (Go crypto/x509 denylist); both checked in this audit
Primary operational risk Non-browser trust stores and pinned clients that never received the block

What actually happened

eMudhra created a batch of 24 intermediates on 30 April 2025 during a Key Generation Ceremony. The batch covered three series (A, B, C), two key types (RSA-4096 and P-384), and four purposes (DV, OV, EV, code signing). The A-series certificates were revoked and replaced by an A-1 series in May 2025. The compromised set is every P-384 key in the B and C series: eight certificates.

According to eMudhra, the ceremony used FIPS 140-2 Level 3 HSMs. A wrap/unwrap step intended to test key export produced a second, weaker key pair on the HSM. Similar key labels caused the weaker pair to be selected for the CSR, signed by the root, and sent to Sectigo for cross-signing. The published public keys therefore correspond to the weak private keys, not the intended strong ones. eMudhra says there is no evidence of infrastructure compromise or data breach, and that it has not yet confirmed the exact code-level root cause.

That account matters for two reasons. First, the failure was in key generation and key selection, not in P-384, ECDSA, or the HSM's cryptographic boundary. Second, "HSM-backed" is not a synonym for "correct." An HSM will faithfully generate a weak scalar if it is asked to. The control that failed was procedural and script-level: the wrong key object was enrolled, and nobody independently checked that the certificate's public key matched the intended key.

Mozilla's investigation supports an independent confirmation. Mozilla's bug comments state that Mozilla recovered the private keys on 17 October (exact time not verified). Mozilla also reports testing local AI agents with a simple CTF prompt; they recovered a key on the first attempt. That test claim has not been independently checked.

The mathematics: why 255 guesses is a total break

A P-384 private key is an integer d selected uniformly from 1 to the group order n, where n is close to 2^384. The public key is Q = dG. Recovering d from Q is the elliptic-curve discrete logarithm problem, believed to require roughly 2^192 work for P-384.

The affected keys do not use the full range. Their d is below 256. In binary, that means every byte except the last is zero. An attacker does not need Pollard's rho, a side channel, or the HSM. They generate G, 2G, 3G, … 255G, compare each point to the certificate's public point, and stop when it matches.

The cost is negligible: a few milliseconds in Python, microseconds in optimized code. Mozilla describes recovery via baby-step giant-step or, more simply, by generating the first 256 P-384 keys. Public analysis reported one recovered key with d = 4; that specific value is secondary reporting, but it is consistent with the range. Whether the value is 4 or 200 does not change the outcome.

This is not a partial weakness that reduces the safety margin. A 384-bit curve with a private scalar below 256 has at most 8 bits of entropy. The certificate's key is effectively public.

The eight certificates

The incident JSON lists eight unique intermediates (six TLS, two code signing). Each appears twice: once under an eMudhra root and once under Sectigo's AAA Certificate Services, sixteen entries in total.

Intermediate Purpose Issuing root (incident JSON) Cross-sign Notes
EM DV TLS CA - G3B DV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM OV TLS CA - G3B OV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM EV TLS CA - G3B EV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM DV TLS CA - G3C DV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM OV TLS CA - G3C OV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM EV TLS CA - G3C EV TLS emSign Root TLS CA - G3 AAA Certificate Services TLS
EM OV CS CA - G3B Code signing emSign Root CS CA - G3 AAA Certificate Services Code signing
EM OV CS CA - G3C Code signing emSign Root CS CA - G3 AAA Certificate Services Code signing

Root naming is a conflict, not resolved here. The incident JSON lists emSign Root TLS CA - G3 and emSign Root CS CA - G3 as the direct issuers, and emSign ECC Root CA - G3 as a cross-signer. eMudhra's statement says the intermediates "sit under eMudhra's ECC root" and that the browser root programs distrusted that root as a precaution. The JSON and the statement disagree on the direct issuer. The browser removals name emSign ECC Root CA - G3.

The TLS intermediates had notBefore values of 30 April 2025, and the Sectigo cross-signed variants 14 May 2025, per the incident JSON. eMudhra-issued CRL entries carry revocation timestamps of 18 October 2026, 09:24–09:38 UTC. The Sectigo cross-sign entries carry 19 October 2026, 10:35:36 UTC. All entries list reason: ca_compromise. These times come from the JSON; the CRLs themselves were not fetched in this audit.

[INFERENCE] Each TLS intermediate appears to have the same subject key identifier under both chains, because a cross-sign does not create a new key. If so, blocking the SPKI hash blocks both the emSign and Sectigo paths at once. Chrome's CRLSet entry was keyed to SPKI hashes, per its blog.

Timeline and the one unresolved discrepancy

Date (UTC, 2026) Event
17 October, 18:05 Chrome's blog records the report
17 October, 19:45 Chrome's CRLSet block for the TLS intermediates is complete
17 October, 20:06 Mozilla receives the report, forwarded by Chrome
17 October, 21:28–21:29 eMudhra acknowledges the report to Mozilla (bug comments give both times)
17 October, time not verified Mozilla independently recovers the private keys (per bug comments)
17 October, 22:59 Mozilla completes OneCRL distribution
17 October, late evening IST eMudhra's statement says it was made aware of the issue
18 October, 09:24–09:38 eMudhra-issued intermediates appear on CRLs
19 October, 10:35:36 UTC Sectigo cross-signed entries carry revocation timestamps, per incident JSON
19 October Apple distrust of the chain, per eMudhra's incident page
19 October, ~22:00 Android receives the block through Google Play Services
20 October Microsoft distrust of the chain, per eMudhra's incident page
20 October Firefox 158.0.1, ESR 115.43.1, ESR 153.5.1 released
21 October, time not verified Firefox for Android 158.0.2 released (version confirmed in bug comments)
27 October (PDT) Chrome root removal scheduled

eMudhra's statement says it was made aware on 17 October, late evening India time, and that it revoked all eight intermediates on 18 October. Mozilla received the report at 20:06 UTC on 17 October. The disagreement is hours, not days. The CA's final root-cause report should reconcile the exact sequence; a blog should not invent a single authoritative timeline where the primary sources disagree.

Why browsers acted on SPKI first and roots second

A browser has two distinct levers:

  1. Block a specific intermediate. Chrome distributed a CRLSet entry keyed to the intermediates' SPKI hashes. Firefox used OneCRL. These mechanisms apply without a browser restart and can be propagated in minutes to hours.
  2. Remove a root. This is broader, slower, and affects every certificate under the root, including unrelated intermediates. Chrome scheduled removal of emSign ECC Root CA - G3 for 27 October PDT. Mozilla's NSS 3.131.1 (20 October 2026) also removes trust in that root (Bugzilla 2084101), per the NSS release announcement. Chrome's and Mozilla's actions are separate.

The SPKI block is narrower and faster. The root removal is the durable control for clients that do not consume OneCRL or CRLSet, but it also creates collateral for any other hierarchy under that root. That is why the two steps are days apart.

Chrome's write-up contains a detail worth understanding: before the block, the six TLS intermediates had no certificate-transparency entries for end-entity certificates. A certificate that is not in CT cannot be used against a CT-enforcing client, but it can still be used against clients that do not enforce CT. Absence from CT is evidence of non-use, not proof that the key was never abused offline.

What each party changed

Party Action Status as of 21 October 2026
eMudhra Revoked all eight intermediates; stopped issuing under the G3 root Complete
Chrome SPKI-hash block for six TLS intermediates via CRLSet Complete 17 October
Chrome Root removal for emSign ECC Root CA - G3 Scheduled 27 October PDT
Mozilla OneCRL block for all eight Complete 17 October, under 3 hours
Mozilla Firefox 158.0.1, ESR 115.43.1, ESR 153.5.1 Released 20 October
Mozilla Firefox for Android 158.0.2 Released 21 October
Google Play Services Android / Googlebook trust update Rolled out from 19 October ~22:00
Apple Distrust of affected chain 19 October, per eMudhra's incident page
Microsoft Distrust of affected chain 20 October, per eMudhra's incident page
Cloudflare Updated WARP/1.1.1.1 clients, cloudflared, CDN and Zero Trust mitigations WARP 20 October 02:00; cloudflared 20 October 09:15; server-side 20 October 19:20
Go crypto/x509 denylist in 1.26.10 and 1.27.3 Released 21 October
NSS consumers NSS 3.131.1 Released 20 October; removes emSign ECC Root CA - G3

Cloudflare's advisory is useful because it separates the browser problem from the server problem. Cloudflare found no active exploitation on its own services, but it had to update shared trust stores, base images, and products that authenticate origins or remote endpoints. Its customer guidance is blunt: updating an SDK may not change the verifier underneath it, and certificate errors after the update must not be "fixed" by disabling verification.

Trust-store status: browsers are the easy part

The tracking site maintains the most complete public matrix. The following table is a snapshot, not a permanent truth; verify the current package version before acting.

Platform / stack Fixed version or action Status
Firefox 158.0.1, ESR 115.43.1, ESR 153.5.1; Android 158.0.2 Published
Chrome / Chromium SPKI block applied; root removal 27 October Partial
Android Play Services trust update Rolled out
Apple platforms OS / trust-store update 19 October per eMudhra incident page
Microsoft platforms OS / trust-store update 20 October per eMudhra incident page
Debian / Ubuntu ca-certificates 20250419~deb12u2, 20250419+deb13u1, 20260816+nmu1 Published
RHEL / Fedora Updated ca-certificates Published
Alpine Updated ca-certificates Published
NSS 3.131.1 Published
Go 1.26.10 or 1.27.3 Published
Node.js 22.23.4, 24.22.1, 26.12.1 Published
Python certifi 2026.10.19 Published
Rust rustls-webpki 0.103.16 Published
Electron Rebuild against updated Chromium/Node; verify the app's bundled store App-dependent
Homebrew ca-certificates 2026-09-25_1 Published
Composer 1.4.16 or 1.6.0 Published
curl (bundled CA) Updated bundle or OS store Published
FreeBSD ca_root_nss 1.131.1 Published
Java 27.0.1.0.2, 25.0.5.0.2, 21.0.13.0.2, 17.0.21.0.2, 11.0.33.0.2, 8u511 Published
Bun No fixed release listed on the tracking site snapshot Pending
Erlang certifi No fixed release listed on the tracking site snapshot Pending

Two caveats are easy to miss:

  • macOS is not one trust store. Some tools, including certain curl, git, and Python builds, load a bundle from a path such as /etc/ssl/cert.pem. Updating the OS may not update the bundle a particular tool loads, and this article did not verify how that bundle handles revocation. Check the path the tool actually uses.
  • A base image is a snapshot. Rebuilding a container does not help if the Dockerfile pins an old digest, copies a CA file from the host, or installs a vendored bundle inside the application. Check the bundle inside the running container, not the build log.

How to test your own clients without fooling yourself

The incident site lists these test hosts. Their DNS records resolve; what they serve, and whether they will stay up for this purpose, has not been verified.

curl https://dv-g3b-emudhra.we-have-a-problem.com/
curl https://dv-g3b-aaa-emudhra.we-have-a-problem.com/

The interpretation is counter-intuitive and often reported backwards:

  • A certificate error means the client does not trust the compromised intermediates. That is the desired result.
  • A clean TLS connection means the client still trusts the compromised chain. That is a failure.

Do not treat every connection failure as a pass. A failure can also come from DNS, a proxy, a firewall, an expired test certificate, or a hostname mismatch. Confirm the error is a certificate-verification error for the eMudhra chain, not a generic network error. Test the exact binary and trust configuration that the application uses, not only the system curl.

For a live chain, inspect what the server actually sends:

openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null \
  | openssl crl2pkcs7 -nocrl -certfile /dev/stdin \
  | openssl pkcs7 -print_certs -noout

On LibreSSL-based macOS tools, the first s_client command may exit 1 even though the pipeline produces output; scripts using pipefail may report a failure. Tested with OpenSSL 3/4.

For a certificate file, print subject, issuer, and SPKI hash:

openssl x509 -in cert.pem -noout -subject -issuer
openssl x509 -in cert.pem -noout -pubkey \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256 -binary \
  | openssl base64

The SPKI hash is the right identifier for the key, not the certificate serial or the subject name. The same key appears under both the emSign and Sectigo chains.

Verify the weak-key claim yourself

This is a read-only check and needs only the public certificate:

from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import ec

def find_small_scalar(cert_path: str, limit: int = 256):
    with open(cert_path, "rb") as f:
        cert = x509.load_pem_x509_certificate(f.read())
    target = cert.public_key().public_numbers()
    for d in range(1, limit):
        cand = ec.derive_private_key(d, ec.SECP384R1()).public_key().public_numbers()
        if (cand.x, cand.y) == (target.x, target.y):
            return d
    return None

print(find_small_scalar("intermediate.pem"))

This example requires the cryptography package. If it is missing from the system Python, use python3 -m pip install cryptography or an isolated environment such as uv run --with cryptography python weak-scalar.py.

A non-None result means the private key is recoverable. Do not use this as a substitute for inventory: there are legitimate ways to have a small test scalar in a lab, and there are other weak-key patterns that this check does not cover.

The Go CVE: a denylist, not a crypto bug

The Go issue (82345) and GO-2026-6809 were checked in this audit. The code-level description below was not checked against the commit diff.

Go assigned CVE-2026-111943 (GO-2026-6809) to its trust-store response. The advisory is careful: on most platforms Go uses system roots, so an updated OS protects Go programs automatically. In narrower cases, a program may still trust the compromised intermediates. To close that gap, crypto/x509 now returns an error when a verified chain contains one of the known compromised intermediates.

The fix work is in issue 82345: backports to release-branch.go1.26 (aa64342a9e13affffea3e989d67e574475af5a78) and release-branch.go1.27 (90617fb7ceb59cf08bee7826bb51b8c8fb8c11de), with the master change in CL 851047 (go.dev/cl/851047). The SHA-256 SPKI denylist and the Darwin and Windows verifier filtering described here were not checked against the diff. The affected API is crypto/x509.Certificate.Verify. Fixed releases are Go 1.26.10 and Go 1.27.3, per eMudhra's status page.

Calling this "a Go vulnerability" is imprecise. The CA key generation was the defect. Go assigned a CVE because a downstream trust decision changed, and enterprises need a tracking identifier for their scanners and change records. Do not let a scanner ticket obscure the actual remediation: update the verifier, and stop trusting the chain everywhere it is trusted.

Enterprise exposure: where this actually hurts

The public web came out relatively well. eMudhra says seven of eight intermediates were never used in production, and that the one production TLS intermediate issued no end-entity certificates. crt.sh was not queried in this audit, so these claims are unverified. Chrome observed no CT entries for the six TLS intermediates. That limits evidence of public misissuance. It does not eliminate the following exposures.

Exposure Why it matters Action
Internal PKI and private trust stores A private CA may have copied the intermediate or root into an internal bundle; CT would never show it Inventory all trust anchors, including test/lab clones
mTLS client authentication Client certificates under the chain may fail after peers update, or may still be accepted by lagging peers Reissue client certs; coordinate cutover by verifier
Code signing Two intermediates could sign code; timestamping and revocation policy determine whether old signatures still validate Re-sign release artifacts; test on clean VMs
Certificate pinning Mobile apps and IoT clients that pin the intermediate or SPKI will break when the block lands Ship a new pin set before the root removal
TLS inspection proxies A proxy that trusts the chain can be used to intercept its own users Update the inspection trust store; audit upstream chains
Java keystores Many apps ship a bundled cacerts that is years old Update the JDK or rebuild the trust store; test the app's actual keystore
Embedded devices NAS, printers, VPN portals, IPMI, industrial HMIs often ship frozen bundles Vendor firmware or isolated network segment; do not assume "it is internal"
Build and CI images A stale builder can sign or verify with the old bundle and fail intermittently Rebuild images from updated bases; pin by digest
Server-side clients Services that call external APIs or origins with a custom store may still accept a forged chain Update the store and the verifier; do not disable verification to clear errors

One more distinction: the root distrust and the intermediate block have different blast radii. A client that still trusts the root can validate a certificate from a different, uncompromised intermediate under that root. A client that has removed the root cannot. Do not assume that blocking the eight known intermediates is equivalent to removing the root everywhere.

Remediation plan

First 24 hours

  1. Inventory every trust store in the estate: OS, language runtimes, browsers, Java, containers, appliances, CI runners, and mTLS peers.
  2. Update the high-value verifiers first: public TLS termination, service mesh, API gateways, code-signing verification, and TLS-inspection proxies.
  3. Test with the actual verifier. Use the incident test hosts and your own chain, and confirm that the failure is a certificate error rather than DNS or proxy noise.
  4. Reissue server certificates that chain to an affected intermediate. Do not wait for clients to update; present a chain that validates against an unaffected root.
  5. Check pins. If a mobile app or device pins the old intermediate, prepare an update before the root removal, not after the outage.
  6. Do not disable verification to silence errors. That converts a trust-store update into a new vulnerability.

First week

  1. Rebuild container images and CI runners from updated bases; verify the bundle inside the running container.
  2. Re-sign code artifacts and packages where the signer chained to the affected hierarchy; test signature validation on a clean machine.
  3. Search logs and CT for certificates issued under the affected intermediates, including internal CT logs if you operate them.
  4. Review third-party and vendor attestations. "We use an HSM" is not an answer to "which key generated this certificate?"
  5. Reconcile the timeline with your own certificate inventory: when did each certificate appear, and which clients could have accepted it?

First month

  1. Add weak-key checks to CA and certificate linting. A small-scalar check is cheap and catches an entire failure class.
  2. Require independent verification that the certificate's public key matches the intended private key before signing. Similar labels are not an identity.
  3. Add trust-store drift detection to container and appliance inventories. Alert when a bundle's digest has not changed across a known update window.
  4. Revisit pinning and hard-coded trust. Pinning is an availability trade-off; document the rotation plan and test it.
  5. Tabletop the next CA incident: who owns trust stores, who can reissue, and who communicates breakage?

Detection and incident response

If you suspect the keys were used, the evidence will not look like a typical web exploit.

  • Certificate-transparency monitoring. Watch for new certificates chaining to the affected intermediates or to emSign ECC Root CA - G3. Even after the block, a logged certificate is evidence that a key was used.
  • Chain anomalies. Alert on upstream chains containing the eight intermediates, especially from internal services that should not use a public CA.
  • Unexpected trust anchors. Compare the trust store of each running container and appliance to the vendor's current bundle. A digest frozen before 18 October is a finding.
  • Pinning failures. A client that suddenly fails where it previously succeeded may be pinned to the old chain. That is a symptom, not necessarily an attack.
  • Code-signing failures. A spike in signature validation failures after a trust update can indicate artifacts that need re-signing.
  • Interception indicators. New TLS termination points, unexpected upstream proxies, DNS changes, or BGP anomalies in paths that carry sensitive traffic.

If a forged certificate is suspected:

  1. Preserve the certificate, chain, and serving logs before rotating anything.
  2. Determine which verifiers accepted the chain: browsers, mobile apps, internal services, mTLS peers, code-signing tools.
  3. Revoke and reissue from an unaffected hierarchy; update pins and trust stores in one coordinated window.
  4. Treat credentials and sessions as potentially exposed if traffic was intercepted.
  5. Report to the CA, the relevant root program, and any regulator required by your jurisdiction.

What the CA and the ecosystem should learn

  • Key ceremony controls must bind identity to key material. A label is not a control. The public key in the CSR must be checked against the intended key, with a second person and an automated check.
  • Weak-key detection belongs in the pipeline. Enumerating small scalars is trivial. It should run before a certificate reaches a CT log or a root program.
  • Revocation is not a universal fix. Many clients do not check CRLs or OCSP. Root removal and vendor updates are the durable controls, and they are slow.
  • The long tail is the real exposure. Browsers can flip a switch. Java keystores, appliances, and bundled bundles cannot. Plan for months, not hours.
  • Timelines must be reconcilable. When the CA's account differs from relying-party logs, publish timestamps and explain the gap. Do not paper over it.
  • "Not in CT" is not "not used." It is evidence, not proof. Private PKI and non-CT clients are outside that evidence.

Technical FAQ

Was P-384 broken?

No. The curve and ECDSA are intact. The private scalars were generated outside the expected range. A 384-bit curve with an 8-bit scalar is weak because of the scalar, not the curve.

Does this let an attacker impersonate any website?

Only for a client that still trusts the affected chain and only if the attacker has recovered a key and minted a certificate. Public CT data shows no end-entity certificates under the six TLS intermediates before the block, which limits evidence of public-web misissuance. Internal, pinned, and non-CT clients remain separate risks.

I updated Chrome and Firefox. Am I done?

No. Check servers, containers, Java applications, mTLS peers, code-signing verifiers, and embedded devices. Browsers are the most visible relying party, not the only one.

Why did Chrome wait until 27 October to remove the root?

Root removal is broader and slower than an intermediate block. It affects every certificate under the root, must propagate through update channels, and can break unrelated hierarchies. Chrome blocked the six TLS intermediates by SPKI hash on 17 October to reduce immediate risk while the root removal was prepared.

Is CVE-2026-111943 the vulnerability?

It is a tracking identifier for the Go trust-store change. The underlying defect is eMudhra's key generation. Go's fix is a denylist in crypto/x509 so programs that do not pick up the OS update still reject the known intermediates.

Does session.upload_progress or memory_limit matter here?

No. Those belong to the separate PHP2Shell analysis. This incident is a PKI key-generation failure; PHP configuration has no effect on it.

Known limitations

  • The exact code-level root cause of the KGC script error has not been published. eMudhra says its investigation is ongoing.
  • The production-use claims are eMudhra's own statements. crt.sh was not queried in this audit. CT does not cover private PKI or non-CT use.
  • The Bun and Erlang rows reflect the tracking site's snapshot around 20 October 2026 and may have changed. The Java row was updated with the 21 October OpenJDK advisory.
  • The d = 4 example is secondary reporting, not a value we independently recovered. The range below 256 is confirmed by Mozilla's primary analysis.
  • The exact number of clients that still trust the chain is unknowable; any estimate would be a guess.

Sources and further reading

Update history

  • 22 October 2026: Added code-level Go denylist analysis, corrected the test-host interpretation, corrected "256-bit key" to "numeric scalar below 256," updated FreeBSD to ca_root_nss 1.131.1, added the KGC wrap/unwrap root cause and the independent Mozilla key recovery.

AI Security Starter Training

Request a practical checklist for prompt injection, RAG data leakage, MCP risks, and model-file security before launch.

Prompt injection and guardrail bypass checks.
RAG data leakage and permission-boundary review.
MCP identity, transport, and command-risk controls.

No spam. Used only to send the resource and related security notes.

Related Research

Related Services

Scope Estimator

Get a rough engagement size before the scoping call.

Estimated engagement

5–7 days

Request exact scope