Security firewall for AI agents

The wall between an AI agent and its actions.

Agents can run shell commands, touch files, and call the internet. ActionWall inspects every action before it executes against a YAML policy you control, and returns ALLOW, ASK HUMAN or BLOCK, with a tamper-evident audit trail.

npm install actionwall· MIT · TypeScript · Node ≥ 20
actionwall · agent terminal
$ actionwall demo
1/9Read the project README● ALLOWED
2/9Run the test suite (npm test)● ALLOWED
3/9Fetch repo metadata from the GitHub API● ALLOWED
4/9Call third-party API with leaked keySEC-OPENAI-KEY● BLOCKED
5/9Read environment variables (.env)CMD-SECRET-FILE-READ● BLOCKED
6/9Fetch cloud metadata (SSRF)URL-METADATA● BLOCKED
7/9Read the user's SSH private keyFP-PROTECTED-READ● BLOCKED
8/9Page content contains prompt injectionINJ-SINGLE-PATTERN◆ ASK HUMAN
9/9Clean up the whole project (rm -rf)CMD-RM-BULK-DELETE● BLOCKED
Why

Guardrails inside the model are probabilistic.
Actions need deterministic control.

Prompt-injection classifiers judge words. But the damage an agent can do happens through actions, and an action either violates your policy or it doesn't.

🎭

Agents follow instructions from content

A web page, an issue, or a file the agent reads can carry injected instructions. Some get through any classifier. The resulting action is the reliable place to stop them.

💣

One hallucinated command is enough

rm -rf with the wrong glob, a credential pasted into a tool call, a request to cloud metadata: agents don't need to be malicious to be destructive.

🕵️

"Trust me" isn't an audit trail

After an incident you need to know exactly what ran, what was blocked, and why. ActionWall logs every decision, hash-chained and verifiable.

How it works

One function between the agent and its tools

Integrate in any tool-calling loop: OpenAI, Anthropic, LangChain, your own framework. If it can build an action object, ActionWall can gate it.

AI Agent

wants to execute an action

rm -rf /project/*

→

ActionWall

runs six scanners against your policy

  • Tool permissions
  • Command risk analysis
  • File access policy
  • Secret detection
  • URL / domain policy & SSRF guard
  • Prompt-injection heuristics
→

Decision

severity → verdict, per your thresholds

ALLOWASK HUMANBLOCK
→

Tools / Internet

only if the firewall allows it

Every decision is appended to a hash-chained audit log.

The headline rule

"Destructive" isn't an opinion. It's a number.

ActionWall doesn't pattern-match the word rm. It expands the target against the real filesystem (read-only, bounded) and counts what would actually be deleted.

actionwall · check
$ actionwall check "rm -rf /project/*"
🔴 BLOCKED · CRITICAL
rm would delete 12 files; policy allows at most
10 automatic deletions.
policy: file_policy.max_bulk_delete

Measured blast radius

Same intent, different verdicts: deleting 5 build artifacts is normal work; deleting 12 project files breaches file_policy.max_bulk_delete. The policy knob is yours; the measurement is the firewall's.

Beyond the bulk limit: protected paths (.env, ~/.ssh/**, .git/**), workspace containment with traversal-proof normalization, SSRF guards for cloud metadata endpoints, credential signatures + entropy detection with automatic redaction, and per-agent tool policies.

Principles

Engineered like a firewall, not a filter

The design decisions are documented and defensible. Every one of them is in docs/ARCHITECTURE.md.

●Fail-closed by default

If a scanner crashes, the action is blocked. Opening the firewall is always an explicit, greppable policy flag.

●Never executes, never phones home

Zero network calls, zero command execution inside the firewall. Filesystem access is read-only and bounded.

●~1–5 ms per decision

Deterministic rules, not model calls. Latency your agent's tool loop won't feel.

●Policy-as-code

YAML policies, zod-validated, with a validate command and CI-friendly exit codes (0 / 1 / 3 / 2).

●Tamper-evident audit

Every decision is a SHA-256 hash-chained record. actionwall log --verify proves the trail is intact.

●Honest about limits

Heuristics are bypassable; this is a policy gate, not a sandbox. The threat model says exactly where the walls are.

Quickstart

Running in two minutes

# inspect any action before it runs
$ actionwall check "sudo chmod 777 /etc/hosts"
$ actionwall check '{"tool":"http.request",
    "params":{"url":"http://169.254.169.254/"}}'

# watch the scripted demo agent
$ actionwall demo
// integrate in any tool-calling loop
import { ShieldEngine, loadPolicy, makeAction } from "actionwall";

const engine = new ShieldEngine(loadPolicy());
const decision = engine.check(
  makeAction({ tool: "shell",
               params: { command: "rm -rf build/*" } })
);
if (decision.verdict === "BLOCK") throw new Error(decision.summary);