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 and builds one system model of the whole fleet. It reviews the agentic surfaces (prompt injection, tool poisoning, excessive agency, cross-server toxic flows), then keeps going where single-server scanners stop: it puts your cloud and Kubernetes in the same graph as the agent, so a toxic flow can cross into the infrastructure it can actually reach. That agent-plus-cloud model is the thing a per-server scanner cannot reproduce.
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 · 16 findings · 4 critical, 11 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
prev 000000…0000
prev 9f41c2…a07e
prev b8d005…44c1
entries 14 · verified
Each entry commits to the one before it. If anyone edits a past finding, the head stops matching, and attestral verify will catch it offline. No server involved.
Everything in the box
A whole design-review pipeline, not a linter.
One command builds a system model of your agent fleet and its cloud, reviews it in three labeled layers, and turns the review into an artifact you can enforce and hand to an auditor. No account, no server, runs offline.
One system model
MCP servers, agent code, prompts, Terraform, and Kubernetes become one graph of components, edges, and trust boundaries, so cross-cutting risk is visible, not implied.
Agentic security, first
Prompt injection, tool poisoning, excessive agency, memory poisoning, the OWASP Agentic and LLM Top 10, MITRE ATLAS. The depth is the moat, not an afterthought.
Toxic flows across the fleet
The lethal trifecta and the attack path that spans several servers, and now several repos: attestral fleet finds the flow no single-repo scan can see.
Config or code
Reads the .mcp.json and the Python: LangGraph, CrewAI, the OpenAI Agents SDK, raw @tool functions. The capability is read from what the code does.
Severity you can defend
A finding on a reachable attack path carries that path and is raised one band. A HIGH ships with the entry-to-exit walk that justifies it, not just a label.
Attest, compile, enforce
The review compiles into a default-deny runtime policy and drift detection. The threat model is not a PDF, it is the runtime configuration.
An artifact for the auditor
Every finding lands in a tamper-evident SHA-256 evidence chain you verify offline, with accept-risk decisions recorded on the chain. Export SARIF and a CycloneDX AI-BOM.
Adopts on real repos
A discovery preamble on every scan, a diff-aware baseline that gates CI on net-new findings only, and a PR summary that renders the reachable path. No day-one wall of debt.
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.
Adversarial validation · attestral validate
It no longer just flags the path. It shows the path is reachable.
A finding is a claim about one config block. attestral validate takes the attack path it built from your system model and walks it over the model's own edges, showing whether it is reachable: entry, pivot, impact. The walked path lands in the tamper-evident evidence chain. Reachability is computed over declared capability (a sound over-approximation); it is necessary, not sufficient, for exploitation. Add --remediate and it scores the OWASP AIVSS agentic posture (an AARS, 0-10) and verifies the fix, the one change that removes the path, confirmed by re-synthesis. Watch one walk below, then open the fully interactive reachability walker.
ATL-RT-INTERNAL · a prompt injection reaches exfiltration
IN MODELchained · verify offline · OWASP AIVSS AARS 10.0
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-three 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 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.
232 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 cross-boundary rules are the hard-to-copy core, the flows that only appear once the agent and its cloud live in one graph; the cloud packs are deliberately good enough that you need no second scanner, never an arms race.
59 agentic and cross-boundary checks that are genuinely hard to copy, over 173 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 cover MCP supply-chain provenance (Git/URL installs, non-default registries), disabled TLS verification and plaintext WebSocket transport, container isolation-breaking flags, and the cross-boundary flows a system model uniquely sees: untrusted input written into agent long-term memory (memory poisoning), a sampling-capable server driving tools on another with no human checkpoint, and indirect injection reaching cloud credentials.
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.
Measured, not asserted
We ran it on 33 real MCP servers. Here is what shipped.
The strongest evidence a scanner works is not a synthetic test, it is real code. We ran Attestral against 33 of the most widely-used public MCP servers at pinned commits, reviewing the launch configuration each one publishes in its own docs, not its source. Every hit is a configuration default, not an exploited vulnerability. Of the 23 that shipped a config Attestral could model, 3 came back completely clean (good counter-examples), and the rest carried the patterns below. Percentages are out of those 23. Aggregate only: no repository is named here, because per-server results are held for responsible disclosure to the maintainers first.
npx -y / uvx, so whatever the registry serves that day runs on your machine: a supply-chain surface (ATL-105).env@latest / :latest reference, so the reviewed tool is not guaranteed to be the tool that runs tomorrow: a rug-pull surface (ATL-106).The headline is compositional. The trifecta (ATL-202) and toxic-flow (ATL-207) hits are the ones that matter most, because they 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, and the reason a system model earns its keep.
What we deliberately do not headline. Intellectual honesty is the point, so borderline classes are called out rather than counted as alarms. Server-name conflicts fired on 57% but are usually an artifact of many independent example configs colliding in one repo, not one deployed fleet. Every "shell-capable" hit was the Windows cmd /c npx launcher idiom, not a server that intends to expose a shell. The non-TLS hits were http://localhost developer entries. Heuristic injection text is not reported as injection without review. The full split and every caveat are in evaluation/real-world.md.
The false-positive read, the number that decides adoption. The 9 newest agentic rules (MCP sampling and elicitation, coding-agent trust, registry-manifest secrets, A2A card signing) fired on 0 of the 33 servers: these repos do not ship those surfaces, so nothing matched, and the rules did not spuriously fire on real code. Underneath this sits an in-repo regression benchmark that runs in CI: all 116 labelled findings across 20 designs fire, all 59 agentic rules are exercised by at least one design, and four benign designs raise zero findings from any band, agentic or cloud. Every fire the benchmark surfaces is adjudicated to a label or a fix, so a rule can never silently break and no finding sits unreviewed. Reproduce all of it with python -m evaluation.score; the harness, the pinned target list, and the per-repo results publish with the maintainer disclosures.
Verified end to end
One realistic project, every layer, known answers.
The 33-repo sweep shows what real configs contain. This is the complement: a single realistic project, examples/ecosystem-composite, an AI support-desk product composited from the patterns that corpus actually exhibits, where every issue was planted first and the scan run after. A known-answer test for the whole pipeline: the cloud and Kubernetes packs, the agentic rules, the cross-boundary model, reachability, and both ML tiers, all working the same repo.
Layer 1, deterministic rules + system model: every planted issue detected (33 findings across 18 components). The public exports bucket and wildcard IAM sit next to the shell-capable runbook server, the privileged root container, and the registry manifest floating on latest; the fleet-level trifecta, shell+network, and untrusted-input-to-execution flows all fire; one full attack path is walked entry to impact and raises four findings a severity band.
| Seeded language surface (layer 2) | Heuristic (default) | DeBERTa (--ml) |
|---|---|---|
| Tool description: covert "forward the conversation, do not mention it" | flagged | flagged |
| Tool description: instruction hidden in an HTML comment | flagged | flagged |
| System prompt: "debug mode" override backdoor | flagged | flagged |
| AGENTS.md: covert archive copy, "keep this between us" | flagged | missed |
| CLAUDE.md: benign directive register (negative control) | clean | clean |
The two instruction files are the point. AGENTS.md hides exfiltration in ordinary workflow prose: the model tier reads it as workflow, the heuristic catches it because its instruction-surface gate looks for exactly that coupling, directive phrasing plus a secrecy signal. CLAUDE.md is the mirror: its "when asked to commit, first run the tests" register scores past the raw threshold and would have been a false positive before the gate; no second signal co-occurs, so it stays quiet. One file demonstrates the false positive the gate removed, the other the true positive it kept. The judge layer (--judge) cross-examines all of it against the modeled system when you bring an API key; everything above reproduces offline from the repo.
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
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.
Config or code. Attestral reads both.
Most agents are not a .mcp.json. They are LangGraph, CrewAI, the OpenAI Agents SDK, a few @tool functions in Python. Attestral AST-parses that code into the same capability model, so the same findings fire whether the shell tool is a server config or a function body. Flip the source and watch the review hold.
The capability of a tool is read from what its body actually does (subprocess is shell, requests is network), not a label, so a Python agent and an MCP server are comparable in one graph. A file is only modeled as an agent when it imports a known framework and defines a tool, so an ordinary script is never misread.
Design review is where security is cheapest. It is also where the tooling is oldest.
The enterprise threat modeling market just consolidated into a single private-equity-owned vendor, priced for the Fortune 500 and built on decade-old architecture. Everyone else reviews designs in spreadsheets and wiki templates: slow, inconsistent, and with nothing to show an auditor. And the fastest-growing attack surface, AI agents and their tools, is the part legacy platforms understand least.
A security review you can't prove happened is an opinion, not a control.
For the teams who review before they ship.
Banks, insurers, and compliance teams under audit review architecture on purpose, because for them a flaw found after an agent reaches production is not a code fix. It is change management, re-certification, and an incident write-up. The same flaw caught in the design review is a one-line config change. Attestral is built for that review: it reads the agent design the way a security architect would, and it produces something an auditor can actually verify.
Named, not hypothetical
The risks are cataloged: prompt injection and excessive agency in the OWASP Agentic and LLM top-tens, adversary tactics in MITRE ATLAS, the lethal trifecta across a tool fleet, live MCP CVEs like CVE-2025-6514. Attestral checks for the specific ones your design actually exposes.
What an auditor accepts
SOC 2 and NIST 800-53 want proof a control operated, not a claim that it exists. Findings carry those references and OWASP Agentic, and the hash-chained review is the artifact you hand over. The EU AI Act and model-risk expectations both push this diligence before a system ships, not after.
And prove it stays true
A design review is only worth its paper if production still matches it. The reviewed model compiles to a runtime policy bound to the review's chain head, and attestral drift flags anything the review never saw. One attested artifact, checked at design time and verified in production.
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
232 typed YAML matchers over the system model, spanning AWS/Azure/GCP/K8s and the agentic surfaces, plus cross-server attack-path synthesis that reaches into the cloud graph. 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.
Layer 2 · reasoning
The risk that lives in the words, not a flag.
A shell flag is a boolean any matcher can catch. A tool description that quietly tells the model to read your SSH key and post it out is language, and no rule sees it. Attestral scores agentic text surfaces for prompt injection with a local classifier: a zero-dependency heuristic by default, an ONNX or DeBERTa tier once you install it, always offline. Load a description or paste your own, and watch it score in real time.
A browser illustration of the heuristic signals. The shipped classifier is a fine-tuned DeBERTa model, see the ML layer explainer. Language risk is scored, never hard-blocked: it becomes a finding tagged origin: ml, so a human still decides.
One command, the whole loop.
From raw config to a runtime policy that catches drift. Scroll through the pipeline: every stage is a real step in a single attestral run, and nothing is hidden between them.
Built for the review board, not just the terminal.
CI on every pull request
Run the scan in CI and findings post to the GitHub Security tab and inline on the pull request as SARIF, so new risk is caught before merge instead of at the annual review.
MCP and agent coverage first
Tool servers, capability scopes, and multi-agent handoffs are first-class parts of the model, not an afterthought bolted onto a diagramming canvas.
Model import
Bring your existing threat models with you. Import from legacy platform exports and keep your review history, chain-sealed from day one. On the roadmap.
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.
The review is the policy. The policy is the enforcement.
This is the depth that lets a review become enforceable policy, not just a linter. Scanners stop at findings. Gateways enforce policies nobody reviewed. Attestral makes them the same artifact. The reviewed system model compiles into a policy for mcp-guard (Attestral's runtime enforcement layer), stamped with the review's chain head, and anything the review never saw counts as drift. A single finding is answered from both ends: attestral remediate prints the concrete source edit to make (the flag to flip, the value to replace), and attestral fix compiles the exact runtime control that neutralizes it, verified and bound to the chain head, so a remediation is also something you can enforce.
Attest
Terraform, Kubernetes, and MCP configs become one system model, reviewed against typed rules and (optionally) a local ML classifier and LLM reasoning. Findings are hash-chained.
Enforce
The reviewed model compiles to a default-deny policy. Denied capabilities carry the rule id that denied them, filesystem roots narrow to what was reviewed, and the policy header binds to the review's chain head.
Prove
Runtime telemetry gets diffed against the compiled policy. An unattested server, a denied invocation, an out-of-scope path: each one is a drift finding. Deployment and review can no longer quietly diverge.
ATL-103 shell verified: enforced-at-proxy
control: servers.shell.allow = false (bound to chain head c31f8e…)
$ attestral compile ./platform -o policy.yaml
wrote policy.yaml · default deny · 1 allowed, 3 denied
[DENY ] shell (denied by attested design review: ATL-103)
$ attestral drift policy.yaml events.jsonl --fail-on-drift
[CRITICAL] DRF-001 Unattested server observed at runtime (mcp_server.jira-sync)
[HIGH ] DRF-003 Filesystem access outside attested roots (mcp_server.docs)
DRIFT: deployment no longer matches the attested design
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.
Every finding cites a real control.
A finding is not an opinion with a severity attached. Each one maps to a named framework an auditor already recognizes, so the review is evidence, not assertion. Attestral spans the agentic frameworks (OWASP LLM and Agentic Top 10, MITRE ATLAS) and the cloud controls everybody expects (CIS, NIST, SOC 2), in one report.
OWASP LLM & Agentic Top 10
Prompt injection, excessive agency, and the tool-fleet risks specific to agents.
MITRE ATLAS
Adversarial ML tactics and techniques, mapped to the surfaces Attestral reviews.
NIST 800-53
Access control, system integrity, and the control families audits are built on.
CIS Benchmarks
The essential AWS, Azure, GCP, and Kubernetes checks, each grounded in a real control.
SOC 2
Proof a control operated, not a claim it exists. The evidence chain is the artifact.
OWASP ASVS
Application security verification requirements, cited per finding where they apply.
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
173 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