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.

$ pip install attestral
$ attestral scan --local

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.

PyPI v0.18.0 Python 3.10+ Zero required deps Runs fully offline Apache 2.0
$ attestral scan examples/vulnerable-agent
Reviewed 6 components across 2 source files: 6 agent / MCP surface

Attack paths (1)
  internal chain: webshellweb  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.

Every finding cites a real control
  • OWASP ASI + LLM Top 10
  • MITRE ATLAS
  • NIST 800-53
  • CIS AWS · Azure · GCP · K8s
  • SOC 2 · ASVS
  • SARIF · CycloneDX AI-BOM
0
security checks
high-signal, each with a fixture
0
clouds modeled
AWS · Azure · GCP · Kubernetes
0
standards mapped
OWASP · NIST · MITRE · CIS · SOC 2 · ASVS
0
review layers
deterministic · ML · LLM

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.

cross-repo

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.

agent code

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.

hover any node to see its reach
agent runtime cloud trust boundary orchestratoragent web-fetchnetwork jirasaas_data ops-shellshell notifymessaging deployshell s3 bucketcloud store iam rolecloud
trust boundary reach / dataflow 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

entry
jira-reader
ingests untrusted input via saas_data
pivot
ops-shell
runs code via shell
impact
web-fetch
exfiltrates via network
REACHABLE
IN MODEL
chained · 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.

$ attestral scan <pasted config>
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.

MCP / Agentichardest to copy
0
Cross-boundaryreachability
0
AWSCIS-grounded
0
AzureCIS-grounded
0
GCPCIS-grounded
0
KubernetesPod Security
0

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.

52%
auto-install an unpinned package
Launch with npx -y / uvx, so whatever the registry serves that day runs on your machine: a supply-chain surface (ATL-105).
48%
expose an unauthenticated remote
A network MCP endpoint with no credential: anyone who can reach it can drive the tools or impersonate the server to the agent (ATL-109).
43%
pass a secret through env
An API token or key handed to the server in its environment, where tool output can echo it back out (ATL-104).
26%
grant outbound network reach
A fetch or browser tool that can reach any URL, including internal metadata endpoints: one half of an exit path (ATL-107).
22%
pin to a mutable tag
A @latest / :latest reference, so the reviewed tool is not guaranteed to be the tool that runs tomorrow: a rug-pull surface (ATL-106).
22%
carry a lethal trifecta
Private data + untrusted input + an exit path in one fleet: the compositional risk that only exists once you model several servers together, which a per-config scanner never sees (ATL-202).

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"flaggedflagged
Tool description: instruction hidden in an HTML commentflaggedflagged
System prompt: "debug mode" override backdoorflaggedflagged
AGENTS.md: covert archive copy, "keep this between us"flaggedmissed
CLAUDE.md: benign directive register (negative control)cleanclean

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

reads private datanothing yet
reaches an exitnothing yet
toggle servers above

Command and control

executes commandsnothing yet
reaches the networknothing yet
toggle servers above

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.


        
attestral scan
ATL-203 · high · shell execution + outbound network in one fleetThe pair that turns an injection into download-and-run.
ATL-207 · high · untrusted input can reach a code-execution toolfetch_page reads the web, run_command runs the shell: a toxic flow.
internal attack path fetch_page (entry) to run_command (pivot) to post_result (exit), synthesized end to end.
identical findings, config or code

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.

Grounded in real threats

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.

Evidence, not assertions

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.

Design time and run time

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.

origin: deterministic

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.

origin: ml

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.

optional · offlineRead the deep dive →
origin: llm

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.

optional · your API keyRead the deep dive →

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.

0.00
paste or load a description

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.

1
Ingest
2
Model
3
Review
4
Evidence
5
Compile
6
Drift

Built for the review board, not just the terminal.

On every change

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.

Agent-native

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.

Roadmap

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.

chain VALID

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.

attestral scan

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.

attestral compile

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.

attestral drift

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.

$ attestral fix ./platform --rule ATL-103
  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.

compiled policy · default deny
jiraALLOW
filesystemALLOW
webALLOW
shellDENY
bound to review chain head c31f8e…9bd4

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.

Agentic

OWASP LLM & Agentic Top 10

Prompt injection, excessive agency, and the tool-fleet risks specific to agents.

Adversary model

MITRE ATLAS

Adversarial ML tactics and techniques, mapped to the surfaces Attestral reviews.

Federal

NIST 800-53

Access control, system integrity, and the control families audits are built on.

Cloud

CIS Benchmarks

The essential AWS, Azure, GCP, and Kubernetes checks, each grounded in a real control.

Attestation

SOC 2

Proof a control operated, not a claim it exists. The evidence chain is the artifact.

Verification

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.

Design review, not SAST

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".

Reachable, not proven

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.

Known blind spots

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.

Be #1, uncontested

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.

Reachability across the fleet

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.

Parity, not volume

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.

$ pip install attestral
$ 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:

# .github/workflows/drift.yml
- uses: attestral-labs/attestral@v1
  with:
    policy: policy.yaml
    events: events.jsonl