Security verification and runtime enforcement for AI agents
AI agents broke security.We rebuilt it.
How it works
Three stages. One pull request your team reviews.
Scan
acme-corp / payments-agent
1/3
Scan
Attack
Protect
GitHub connected · Armorer Security installed on acme-corpDeep agentic analysis · ~18m left5 of 10ETA confidence: medium · heartbeat 4s agoSwipe the map sideways to follow a route end to end →
- Candidate routes
- Connected
- Could not resolve
Routes found
1 critical · 1 high · 1 medium
Exploring how tool calls chain — 3 candidate paths so far
- #1CRITICALemail → browse_web → send_paymentcandidate · potential
- #2HIGHvendor docs → query_ledger exfilcandidate · potential
- #3MEDIUMweb → memory poisoningblocked
What this scan could not see
- Retrieval index — not reachable from the twin
- 2 unknown frontiers on the attack map
“Coverage is not completeness — blind spots stay listed.”
Attack
acme-corp / payments-agent
2/3
Scan
Attack
Protect
Criticalemail → browse_web → send_paymentArmorer copilot
Autonomous · asks when needed
Approve the attack run on path #1? Approved
Isolated rebuilt twin · crafted email injection · no production access
Approve path #1Review the pathSwipe the map sideways to follow a route end to end →
- Proven path
- Connected
- Could not resolve
A crafted email steers the agent to fetch a web page, and what that page says reaches the arguments of a payment.
1
email
untrusted source
2
browse_web
external content
3
send_payment
Stripe API · live key
A drafted $4,900 transfer to an attacker-controlled account
Protect
acme-corp / payments-agent
3/3
Scan
Attack
Protect
BeforeAfter fix2 files changed+18−3armorer/fix-path-1tools/browse_web.py+4 −1def fetch(url: str) -> str:- Removed
return page_text - Added
return Provenance.tag(page_text, source="web", trust="untrusted")
agents/payments_agent.py+14 −2def send_payment(amount, dest, *, ctx):- Added
if Provenance.untrusted_influence(ctx, on=("amount", "dest")): - Added
raise RequireHumanReview("untrusted content shaped payment args") return stripe.transfer(amount, dest)
Why this control?
The cheaper options don’t hold. Blocking browse_web breaks three approved workflows. Filtering the page text is bypassable. Checking provenance at the argument boundary is the narrowest place where the attack must pass and your approved work never does.
Your reviewers merge it — Armorer never merges. Two approvals are required on this repo.
Path #1 · with the proposed control
- Inbound email
untrusted source
- browse_web
- INFLUENCES_ARGUMENTArgument provenance checkcontrol · proposed
inserted at the argument boundary
- BLOCKEDsend_payment
- USES_CREDENTIALStripe API
credential: live key
Verified in the twin before anything ships
- Exploit path #1re-ran 20× in the isolated twinBLOCKED 20/20
- Approved workflowsyour 12 golden tasksSTILL PASSING 12/12
- Added latencyat the consequential action+3.4 ms avg
Customers
A risk question becomes a decision.
“We had an agent we weren't comfortable giving more access to. Armorer showed us how it could be abused. It stopped being a debate about opinions.”
Tilen Terčelj Schweizer · CEO, TILCO Trading Ltd“My worry with a security safeguard is that it quietly breaks something a customer depends on. Armorer made that a test, not an assumption.”
Daniel Sakhai · CTO, HeyHire