A runtime firewall for AI agents.
Agentwall watches what agents actually do on the host, attributes each action to the process that took it, and writes a record that cannot be quietly rewritten. It runs locally, needs no account, and has no paid tier.
Prompts are not a security boundary. An agent that has been argued into leaking a key still holds the key. Agentwall works one layer down, where an action becomes real, and treats the agent as the untrusted party.
Two limits matter more than any feature below.
It defaults to observing. Enforcement exists and is real, but monitor is the default:
egress is evaluated and recorded, and allowed. You opt in with enforcement.mode — guarded
enforces the deny rules that match, strict is allowlist-only. Monitor mode reports what the
other two would have done, so you build the allowlist by reading your own ledger rather than
by breaking your tooling to find out. A firewall that starts by breaking your tooling gets
switched off, and a switched-off firewall protects nothing.
Capture is cooperative. The proxy is found through standard proxy environment variables. A process that ignores them egresses unseen. Nothing here installs iptables or nftables redirection. Agentwall raises the cost of unobserved egress; it does not make it impossible.
The rest are in Limits. They are not footnotes.
Linux, Node.js 22.12 or newer.
npm install -g @repsecure/agentwall
agentwall init --mode monitor
agentwall doctorThe unscoped npm package agentwall is a different, unrelated project. This one is
@repsecure/agentwall.
init writes agentwall.config.yaml and policy.yaml into the current directory. Both are
gitignored, and init will not overwrite work you already have. doctor checks Node, the
build output, and those two files.
From a checkout instead — run node dist/cli.js wherever this file says agentwall:
git clone https://github.com/repsecure/agentwall.git
cd agentwall && npm install && npm run buildEvery variable below is required for the thing it enables.
export AGENTWALL_OPERATOR_TOKEN="$(openssl rand -hex 32)" # without this, every route 401s
export AGENTWALL_AUDIT_FILE="$PWD/audit.jsonl" # without this, the chain is stdout only
export AGENTWALL_PROXY_PORT=8899 # without this, the proxy does not start
agentwall startSend traffic through it from a second shell in the same directory:
https_proxy=http://127.0.0.1:8899 curl -s -o /dev/null https://example.com/
tail -1 audit.jsonlEach request appends a chained record naming the process that made it:
{"agentId":"curl","plane":"network","action":"egress:https","decision":"allow",
"metadata":{"host":"example.com","port":"443","pid":"1101858","comm":"curl"},
"integrity":{"chainIndex":1,"hash":"0e86f943...","previousHash":"4678da51...",
"algorithm":"sha256","status":"chained-local","canon":"cu1"}}The operator console is at http://127.0.0.1:3000/dashboard. A browser cannot send a bearer
header, so for local use start with AGENTWALL_ALLOW_LOOPBACK_DEV=1, which accepts loopback
callers as a loopback-dev principal. Do not set it on a host anyone else can reach.
A verifier written by the same people in the same language as the writer only proves the code agrees with itself. Agentwall ships two independent verifiers and a corpus of deliberate forgeries that runs them against each other on every push.
agentwall verify # bundled TypeScript verifier
cd verifier && go build -o agentwall-verify . && ./agentwall-verify --audit <path>verify reports three layers separately, because they fail independently and one verdict
would hide which guarantee you actually have:
PASS chained records link within each segment, so an edit inside one is detectable
PASS linked segments link and match their files, so replacing one is detectable
PASS anchored a fingerprint exists off-box, so a local rewrite shows
agentwall anchor seals the segment, signs an Ed25519 checkpoint over the head, and submits
the digest to OpenTimestamps for inclusion in a Bitcoin block. No account, no API key. An
anchor stays pending for roughly one to six hours, and pending is not proof.
A signature only proves a key holder vouched. Pin the key you expect with --pubkey-file; a
foreign key exits 1. The Go verifier has zero third-party dependencies — cd verifier && go list -m all prints one line.
Full detail, including the conformance corpus and what verification does not prove, is in docs/verification.md.
- Egress enforcement, in three modes.
monitorevaluates and allows while reporting what the stricter modes would have done;guardedenforces matched deny rules;strictis allowlist-only. A blocked request gets a403and anX-Agentwall-Block-Reasonheader, so a broken agent is a diagnosis rather than a mystery. - MCP servers wrapped, stdio and Streamable HTTP.
agentwall mcp wrapputs every JSON-RPC frame through ordered gates: tool-poisoning and drift on the advertised inventory, secrets and injection in tool arguments, your policy rules, and injection in the tool output the agent is about to read. Same engine, same audit chain, either transport. - An emergency stop with four independent sources. Config, API,
SIGUSR1, or a sentinel file. Any one engages it, each releases only its own hold, and it overrides every mode including monitor. The file channel is the one that still works when the HTTP surface is wedged. - Egress capture with observed identity. A CONNECT-aware forward proxy maps the client
socket back to its owning process through
/proc/net/tcpand/proc/<pid>/fd, so a record carries the realpidandcommeven if the agent lies about who it is. Linux only. Attribution failure degrades topid: nulland never blocks egress. - A policy engine with predictable precedence. Six planes, four outcomes, most restrictive
wins:
deny>approve>redact>allow. Results carry matched rule IDs, plain reasons, a risk level, and MITRE ATT&CK technique IDs. - Hot-reloadable policy. A built-in rule pack plus YAML. A file that fails to parse is rejected whole and the previous ruleset stays in force, so a typo cannot leave you running with half a policy.
- DLP with inline redaction. AWS keys, GitHub PATs and OAuth tokens, OpenAI keys, Slack tokens, private keys, JWTs, SSNs, credit cards, emails, phone numbers.
- SSRF and egress inspection. Scheme, port, and host allowlists blocking private, loopback, and link-local ranges plus cloud metadata endpoints. Shell command preflight and manifest drift detection alongside.
- Approvals and budgets. A persistent approval queue with
auto/always/nevermodes, per-session and per-actor rate limits, pending-approval caps, cost budgets, and session pause, resume, and terminate enforced at/evaluate. - An audit log built for real operation. SHA-256 hash-chained records, a single-writer
O_EXCLlock, torn-tail recovery, and restart-safe resume. A storage failure is reported as a declared gap, never as a deletion, so a full disk and a tampered file do not look alike. - Auth that fails closed. A bearer token compared in constant time on an allowlist model:
every route is protected unless explicitly public, so a route added next year is guarded by
default. Only
/healthand/api/healthare public.
Egress observed by the proxy enters the same hash chain. The request-to-decision-to-audit path is written out in docs/architecture.md; the routes and every environment variable are in docs/reference.md.
Stated plainly, because a security tool that oversells itself is worse than no tool.
| Limit | What it means |
|---|---|
| Monitor by default | Enforcement is real but opt-in. Out of the box the proxy evaluates, records, and allows; guarded and strict are configured, not automatic. Installing this does not block anything until you say so. See docs/enforcement.md. |
Only deny is enforceable on a socket |
approve and redact verdicts are recorded and the request is allowed. A proxy has nowhere to put a held request and no way to rewrite a CONNECT body, so pretending otherwise would be worse than saying it. |
| Cooperative capture | Proxy environment variables are honoured voluntarily. A process that ignores them egresses unobserved. No iptables or nftables redirection is installed. |
| Anchoring is pending, not instant | An OpenTimestamps anchor stays pending until a Bitcoin block confirms, roughly one to six hours. Pending is not proof. |
| Anchoring proves no alteration, not completeness | An anchor shows that what was written was not altered afterwards. It cannot show that everything which should have been written was. |
| A signature is necessary, not sufficient | On a host where the audited principal can read the signing key, an agent with root can sign anything the operator can. Off-box anchoring is what closes that gap. |
| Verifier agreement is bounded by the corpus | The two verifiers return the same verdict on all 26 conformance cases. That is agreement about those cases, not a proof of equivalence, and it says nothing about a forgery neither has been asked to judge. |
| No TLS interception | CONNECT traffic is visible at hostname and port level only. Paths, headers, and bodies stay opaque. MITM would need a CA in every runtime trust store, which breaks the framework-agnostic property the proxy exists for. |
| Attribution is Linux-only | It reads /proc/net/tcp and /proc/<pid>/fd. There is no macOS or Windows equivalent. The rest of the server is portable; process attribution is not. |
| Channel containment is Telegram only | Slack and Discord appear in the platform schema with no route implementation behind them. |
| The watchdog does not auto-deny | It exposes heartbeat age and a kill-switch flag, and a rule denies on the watchdog_timeout label, but nothing wires staleness to that label automatically. Treat it as a signal you act on. |
| Telemetry is off by default | The OTLP/HTTP decision-trace exporter is disabled unless configured. |
| Bearer tokens, not identity | A shared token, not OIDC or mTLS. No identity-provider integration. |
| Single host | Multiple instances can be polled into one summary view. There is no clustered or highly-available control plane. |
TypeScript 5 (strict) on Node.js 22.12+, Fastify 5, Zod, YAML policy via js-yaml, Jest.
Runtime dependencies are deliberately three: fastify, js-yaml, zod. The audit and
anchoring paths use Node's own crypto and plain HTTP with no third-party clients, because a
dependency inside the component whose whole job is being trustworthy is a supply-chain risk
this project declines.
Install · Enforcement · MCP · Kill switch · Architecture · Threat model · Verification · Audit format · API and configuration · Scan API · Explain · Benchmark · Compliance · Canary tokens · Filesystem sentinel · FloodGuard · Tutorials · Changelog
Issues and pull requests are welcome, including ones that show a claim in this file is wrong. See CONTRIBUTING.md, GOVERNANCE.md, and CODE_OF_CONDUCT.md. Security reports go through SECURITY.md, not a public issue.