AI agent & MCP security
The security scanner for AI agents and MCP servers.
Attestral reads your MCP configs, agent code, system prompts, and tool descriptions, builds one system model of the whole fleet, and reviews the agentic surfaces most scanners never look at, from prompt injection to the toxic flows that only exist across servers and repos. It models your cloud and Kubernetes in the same graph, so it sees the trust boundary between the agent and the infrastructure it can reach.
No account, no API key, fully offline. It reads the MCP configs your agents already use, Claude Desktop, Cursor, .mcp.json, and reviews every server it finds.
Reviewed 6 components across 2 source files: 6 agent / MCP surface
Attack paths (1)
internal chain: web → shell → web entry · pivot · exit
[CRITICAL] ATL-202 Lethal trifecta: private data + untrusted input + an exit (model)
[CRITICAL] ATL-103 Shell-capable MCP server configured (shell)
[CRITICAL] ATL-108 Tool calls auto-approved, no human checkpoint (shell)
[HIGH ] ATL-207 Untrusted input can reach a code-execution tool (model)
[HIGH ] ATL-107 Outbound network reach (web) · raised from medium
[HIGH ] ATL-ML-001 Prompt-injection text in a tool description (web)
… and 10 more
6 components · 17 findings · 4 critical, 12 high, 1 medium
A real review of the vulnerable-agent example: two small config files, zero cloud credentials required. The attack path and the lethal trifecta are fleet-level, and ATL-107 was raised to high because it sits on that reachable path. Point it at your own machine with attestral scan --local.
- OWASP ASI + LLM Top 10
- MITRE ATLAS
- NIST 800-53
- CIS AWS · Azure · GCP · K8s
- SOC 2 · ASVS
- SARIF · CycloneDX AI-BOM
How it works
One command. Seven phases. Three layers.
Every scan runs the same pipeline: ingest everything the agent touches, build one system model, trace what can actually reach what, sweep the graph with typed rule packs grounded in current attack research, then seal the evidence and compile the verdict into runtime policy. Follow any phase to watch it run live.
Inside the pipeline, three review layers keep their labels: deterministic rules always run, a local ML tier scores the language surfaces offline, and an LLM judge cross-examines findings when you bring a key. Every finding carries its origin, so a reviewer knows what is reproducible fact, what is a score, and what is reasoning.
What only a whole-fleet model catches
It builds a model of your whole fleet, then reasons across it.
Not a config-by-config scan. Attestral ingests your MCP servers, prompts, cloud, and Kubernetes into one graph of components, edges, and trust boundaries. That is how it sees the path a single injected sentence can take: from an untrusted input, through a shell, across the boundary into your cloud. Hover a node to see its reach, or trace the attack path.
Because the model knows what every surface can reach, findings are not rated in isolation. A prompt-injection hit is raised to critical only when the surface it sits on can reach a secret or an egress channel, and left low when it reaches nothing worth taking. A cross-server tool-name collision is raised when one side is a lower-trust, mutable package positioned to shadow a trusted tool, and look-alike names (a Cyrillic letter, a zero-width space) are folded so an impersonation cannot hide behind a spelling an exact match would miss.
The finding that lives in no single file.
Every server below is individually defensible, and a config-by-config scanner would wave them all through. The risk is compositional: the moment one agent session can read private data and reach an exit, a single injected sentence anywhere in its inputs becomes an exfiltration. Toggle the fleet and watch the pack's combination rules evaluate it live, using the same capability groups attestral scan applies to your real configs.
The exfiltration chain
Command and control
The iframe backdoor
Fleet-level findings only: the per-server findings these toggles would also raise (a shell server is ATL-103 all by itself) are left out here to keep the composition visible. On a real scan the full attack path is also synthesized end to end, entry to pivot to impact.
The flagship
...and no single repo.
Real agent estates span repositories: a data reader in one, an ops runner in another, a notifier in a third. Each repo passes its own review. The attack chain completes only across the boundary, and only a model that spans them can see it. Assign each tool to a repo and watch every per-repo scan stay green while attestral fleet lights up.
attestral scan repo-a
attestral scan repo-b
attestral fleet repo-a repo-b
ATL-213 fires only when the fleet completes a chain that no single repo completes alone. Move all three tools into one repo and it goes silent, because that repo's own scan already catches the flow. It is never noise, and it is the one finding a per-repo scanner structurally cannot produce.
Real systems · aggregate, no repo named
Scanned in the wild: one in three ships the lethal trifecta.
The rest of the evaluation is a synthetic suite with an answer key. This is different: Attestral run across 390 public MCP server repositories. Of the 233 that shipped a modelable configuration, 32.6% carry the lethal trifecta: private data, untrusted input, and an exit path in one fleet. The rate was stable as the corpus grew and survived every correction pass. Every hit is a configuration default, not an exploited vulnerability; per-repo results stay under responsible disclosure until each maintainer has been notified.
The study began as a hand-audited pilot: 33 of the most widely used servers at pinned commits, reviewing the documented launch configuration, the mcpServers block users copy from a README. What the 23 modelable pilot configs contained (percentages are of the 23):
| Pattern | Rule | % of 23 |
|---|---|---|
| Lethal trifecta · private data + untrusted input + an exit, in one fleet | ATL-202 | 22% |
Auto-installs an unpinned package at launch (npx -y / uvx) | ATL-105 | 52% |
| Remote MCP server with no authentication (superseded: under 1% once the check became OAuth-aware, see below) | ATL-109 | 48% |
Secret passed to the server via env | ATL-104 | 43% |
| Outbound network / browser access | ATL-107 | 26% |
Mutable @latest / :latest tag (rug-pull surface) | ATL-106 | 22% |
| Shell execution + outbound network in one fleet | ATL-203 | 9% |
| Toxic flow (untrusted input can reach a sensitive action) | ATL-207 | 9% |
The headline is the compositional one. The lethal trifecta and toxic-flow hits are fleet-level: they exist only once you model several servers, and in one case a committed sub-agent, together. That is the finding no config-by-config scanner produces: nearly a quarter of the pilot, and one in three across the full corpus.
Two per-server pilot numbers were corrected on the way to 390: the no-auth rate was an OAuth false positive and fell to under 1% once the check became OAuth-aware, and monorepo README merges can manufacture a false "fleet." The trifecta survived every correction.
A named per-repo gallery, one screenshot of a genuine trifecta in a project you recognize, publishes as a second wave, after each maintainer has been given a responsible-disclosure window. We would rather be fair to maintainers than fast to a headline.
Don't take the demo's word for it. Paste your own config.
Drop in an .mcp.json or claude_desktop_config.json and twenty-seven of the agentic checks from the rule pack, the same typed matchers the engine runs, review it right here. Everything happens in this tab: the page makes no network request with what you paste. The CLI goes further, with the cloud packs, attack paths, prompt surfaces, and the evidence chain; the playground runs whole fleet scenarios in the browser.
The example is examples/vulnerable-agent/.mcp.json from the repo, the same file the demo above scans.
waiting for a config. Load the example, or paste the mcpServers block your agent already uses.
Why not just Checkov or Trivy?
Keep using them. They are excellent at cloud infrastructure, and attestral is not out to replace them; it scans the same Terraform and Kubernetes with a solid CIS-grounded pack of its own. But those tools were built before agents had tools. They do not parse an .mcp.json, they cannot tell that a tool description is quietly asking the model to read your SSH key, and they have no concept of the trust boundary between an agent and the shell it can call. Attestral does one thing they structurally can't: it builds a system model of your whole agent fleet, so it catches the toxic flows that only exist across servers, where private data meets an exit and one injected sentence walks out with your secrets.
| Capability | Checkov · Trivy · tfsec | Attestral |
|---|---|---|
| Cloud IaC misconfiguration | Mature and deep. Their home turf. | ✓A CIS-grounded pack across AWS, Azure, GCP, and Kubernetes. |
| MCP server configs (shell access, transport, secrets) | Not modeled. | ✓First-class components in the system model. |
| System prompts and tool descriptions | Not parsed. | ✓Reviewed, and scored for prompt injection. |
| Agent-to-tool trust boundaries | No concept of one. | ✓The center of the graph attestral builds. |
| Prompt injection in agentic text | Out of scope. | ✓Local ML classifier, on by default, fully offline. |
| Toxic flows across the tool fleet (lethal trifecta) | No fleet model. | ✓Named source and sink servers, mapped over the graph. |
| Memory poisoning & risky agent skills | Not modeled. | ✓World-writable CLAUDE.md, vector stores, SKILL.md grants. |
| Runtime drift (the running system diverging from the reviewed design) & tool rug-pulls (a tool silently changed after you approved it) | Static only. | ✓Attested design compiles to a policy; drift is caught. |
| Known MCP CVEs & hook config-injection | Not tracked. | ✓Vulnerable package versions and malicious .claude/settings.json hooks (CVE-2025-6514, CVE-2025-59536). |
| Tamper-evident audit evidence | Report only. | ✓SHA-256 evidence chain you verify offline. |
The honest version: run Checkov and Trivy for cloud depth, and run attestral for everything that lives above the infrastructure, the agent, its tools, and the prompts that drive them. It happens to cover the cloud underneath too.
288 checks, and the balance is the strategy.
We do not chase rule count. Every check earns its place with a real control and a fixture. The agentic and cross-boundary rules are the hard-to-copy core, the surfaces nobody else models; the cloud packs are deliberately good enough that you need no second scanner, never an arms race.
99 agentic and cross-boundary checks that are genuinely hard to copy, over 189 cloud checks across AWS, Azure, GCP, and Kubernetes, mapped to 21 named control families across the six standards it cites. Depth where it counts most, parity where it just has to be solid. The newest checks reach further than a config scan: the information-flow lattice that turns the lethal trifecta into a discharge-able property (above), known-CVE scanning of the agent's own dependency manifest (requirements.txt / pyproject / package.json, the surface a config review never reads), and the cross-boundary flows a system model uniquely sees: untrusted input written into agent long-term memory, a sampling-capable server driving tools on another with no human checkpoint, and indirect injection reaching cloud credentials.
Recall you cannot self-grade. The in-repo benchmark scores 174/174, but its labels come from our own fixtures, so we also measure against eight published 2025-2026 CVE advisories labelled from the advisory, not our output. That number is allowed to fall below 100% and does; each miss is itemised with a concrete path to close it. It is how a tool whose product is trust should report its reach.
Proven on real Terraform, tuned against first-scan noise. A pinned regression suite runs the cloud packs against Bridgecrew's deliberately-vulnerable TerraGoat corpus, so what fires today keeps firing tomorrow. The ingester also reads security-group CIDRs direction-aware: the world-open egress block nearly every production repo ships never reads as "open to the world", so a first scan of real infrastructure does not open with a false alarm. A benign real-Terraform design sits in the CI benchmark to keep it that way.
Three review layers. Run each one.
Regulated buyers can't accept "the AI said so." Attestral separates what is deterministic from what is model-reasoned, and every finding carries its origin. Pick a layer and watch it run against the same insecure agent, real commands, the output the CLI actually prints.
Typed rules, fail-closed
288 typed YAML matchers over the system model, spanning AWS/Azure/GCP/K8s and the agentic surfaces nobody else models, plus cross-server attack-path synthesis. No eval anywhere; an unknown matcher never matches. Fully reproducible, free, offline.
Injection text a rule can't see
A DeBERTa-v3 prompt-injection classifier scores the language surfaces an agent reads and can be steered by, tool and server descriptions, system prompts, offline. Three tiers (zero-dep heuristic, ONNX, DeBERTa) emit the same finding shape, so the evidence chain is identical whichever scored.
Cross-examined to cut noise
An LLM judge re-examines each finding and votes confirmed / false-positive / needs-review with a confidence, so the borderline ones (a localhost dev endpoint read as non-TLS) get caught. A confident false positive is auto-waived, never deleted: it stays on the evidence chain with the judge's reasoning.
Tamper with the record. Watch it break.
Every finding commits to a SHA-256 chain: entry N hashes its own canonical JSON together with the hash of entry N-1, from a zero genesis. The head is the integrity commitment for the run. This recomputes live in your browser, the same construction attestral verify uses. Edit one entry and every hash after it stops matching.
That is integrity: the chain is internally consistent. A determined editor could recompute every hash and forge a fresh head, and this check alone would still pass. So attestral sign adds authenticity: an Ed25519 signature over the head, in a DSSE envelope (the Sigstore / in-toto envelope). attestral verify --public-key then catches a recomputed forgery, because re-sealing the chain needs the reviewer's private key. Tamper-evident, and now provably the chain they sealed.
Then the policy watches. Drift gets caught.
The attested design compiled to a default-deny policy. Now runtime telemetry is diffed against it, in batch or as a continuous sidecar: attestral drift --stdin reads a live telemetry pipe and --watch tails the log, streaming drift the moment it happens. What the review saw passes, and what it never saw is drift, each tagged with the rule that caught it: an unattested server, a rug-pull where the served tool schema no longer matches the attested manifest, a runaway loop. This is the loop no scanner and no gateway closes on its own.
Honest by default
What it does not do.
A tool you can trust is one that is honest about its edges. In a field full of overclaiming, the tool that documents where it stops is the one a skeptical engineer keeps. So here are the limits, stated plainly, not buried in a footnote.
It reads the declared surface
Config, agent wiring, prompts, IaC, not the inside of a tool's implementation. It tells you the capability a tool grants and the flows it enables; it will not find a logic bug inside that tool's code. Every scan says so up front, so a clean result never reads as "nothing here".
Necessary, not sufficient
A reachable attack path means the design allows the flow over declared capability. It does not prove the model would follow an injection, or that no guardrail sits in the path. We reframed away from the word "proof" for exactly this reason. A reachable HIGH is worth prioritizing, not already exploited.
And where we break
HCL cross-variable resolution depth, coarse capability classification, a probabilistic ML tier, agent code that needs a recognizable framework. We track a benign false-positive rate in CI and publish where a defense-aware attacker can dodge us. The full list is in docs/limitations.md.
Attestral Labs
Security built for the agentic era, not bolted onto it.
Agents got tools before anyone secured them. The industry's answer was to bolt an agent tab onto scanners built for a pre-agent world. Attestral is built the other way around: a system model of the agent, its tools, and the cloud they can reach comes first, and everything else follows from that graph.
Agentic security is our identity
MCP, prompt injection, tool poisoning, excessive agency, the OWASP Agentic and MITRE ATLAS surfaces. Depth here is the moat, and it is where we invest first.
Architecture, not a linter
One system model lets us reason about agent-to-cloud reachability, secrets crossing a boundary, reachable attack paths, and compile-to-policy drift. That is cross-server reachability across a trust boundary, which a per-file scanner cannot express, no matter how many rules it adds.
Your cloud, covered too
189 high-signal CIS checks across AWS, Azure, GCP, and Kubernetes. Good enough that most teams need no second scanner, never an arms race.
Open source, forever. The core is Apache 2.0 and always will be. The vision is a single artifact that carries a design from review, to proof, to runtime policy, so that "is this agent safe" stops being an opinion and becomes something anyone can verify. See the work on GitHub.
Start in sixty seconds.
No account, no server, no API key. The whole attest → prove → enforce → detect loop runs on your laptop, under Apache 2.0.
$ attestral scan ./my-project # attest: one system model, reviewed
$ attestral verify review.json # prove: chain VALID
$ attestral compile ./my-project -o policy.yaml # enforce: default-deny policy
$ attestral drift policy.yaml events.jsonl # detect: runtime vs. reviewed design
Gate every deploy in CI with the GitHub Action:
- uses: attestral-labs/attestral@v1
with:
policy: policy.yaml
events: events.jsonl