Agent Firewall
A runtime security and governance layer that evaluates AI-agent tool requests
before they execute and returns one of three decisions: allow, ask
(require human approval), or block.
The engine is vendor-neutral and dependency-light (just pydantic + PyYAML)
so it can run inside a Claude Code PreToolUse hook with no network and no
database. The same engine can back an MCP gateway or an HTTP service.
It is a policy gate, not a sandbox. It never executes the tool it is judging, and it only reasons about what the integration hands it. Read
docs/limitations.mdfor the honest threat model before you rely on it.
How it works
Every request flows through a fixed, security-critical pipeline
(src/agent_firewall/engine.py):
- Authorization (fail-closed). Unknown tools and unauthorized agents are
rejected before anything else. (
authorization.py) - Detection. Deterministic detectors appropriate to the action type run:
shell-command shapes, filesystem path analysis, secret/DLP scanning, and
prompt-injection indicators. (
detection/) - Risk scoring. Findings are turned into an additive, fully attributed
0–100 score with per-factor explanations — no learned component. (
risk/) - Policy evaluation. Declarative YAML policies decide
allow/approval/deny, with the risk score available as a threshold. (policies/) - Combine. Precedence is
deny > approval > allow. A high score can only raise scrutiny; it can never rescue a denied request, and a low score can never override adeny.
Each decision is explainable (explanation, matched_policies,
matched_rules, risk_factors) and recorded to a tamper-evident audit log.
Install
Requires Python ≥ 3.11.
pip install -e . # core engine + CLI
pip install -e ".[dev]" # + pytest, ruff, mypy, hypothesis
pip install -e ".[api]" # + optional FastAPI/SQLAlchemy service deps
pip install -e ".[mcp]" # + optional MCP gateway deps
The repo also works without installing: hooks/pre_tool_use.py inserts
src/ onto sys.path itself.
Use it as a Claude Code hook
.claude/settings.json already wires the firewall as a PreToolUse hook over
the file, shell, and network tools:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash|Read|Write|Edit|MultiEdit|NotebookEdit|WebFetch|Glob|Grep",
"hooks": [{
"type": "command",
"command": "python",
"args": ["${CLAUDE_PROJECT_DIR}/hooks/pre_tool_use.py"],
"timeout": 10
}]
}]
}
}
Decision mapping to the hook protocol:
| Engine decision | permissionDecision |
|---|---|
BLOCK |
deny |
ASK |
ask |
ALLOW |
deferred to Claude Code's native flow (nothing emitted) unless AGENT_FIREWALL_EMIT_ALLOW=1 |
Deferring on allow means the firewall never disables native permission
controls — it only ever tightens them. Remove the hooks block (or the file) to
disable it entirely.
CLI
# Evaluate a synthetic request and print the full decision as JSON
agent-firewall evaluate --tool Bash --input '{"command": "rm -rf /"}'
# Validate a policy file against the schema
agent-firewall policy validate policies/default.yaml
# Inspect / verify the audit log
agent-firewall audit show --limit 20
agent-firewall audit verify
(agent-firewall hook runs the same stdin-driven hook adapter directly.)
Use it as an MCP gateway
The same engine can be exposed as a Model Context Protocol server so any MCP client can consult the firewall before running a tool:
pip install -e ".[mcp]"
agent-firewall mcp # serve over stdio
It registers one tool, evaluate_tool_request, that returns an
allow / ask / block decision for a described request. It is a consultative
gate — the calling agent must honor the decision. See
docs/mcp-gateway.md.
Policies
Policies are declarative YAML (policies/default.yaml). Selectors within a
policy are ANDed; lists within a selector are ORed. Effects are allow,
approval, or deny, with deny winning. The bundled set:
block-protected-credentials— never read/write.env, keys,.ssh,.aws, …block-critical-risk— deny anything scoring ≥ 85 (howrm -rf /,mkfs, fork bombs, secret egress get hard-blocked — the score can't be argued away)require-approval-elevated-risk— score ≥ 50 (< 85) needs human approvalrequire-approval-network-egress— outbound tools (WebFetch) need approvalallow-project-reads— reading non-sensitive files is allowed
Configuration
Read from the environment (src/agent_firewall/config.py):
| Variable | Default | Meaning |
|---|---|---|
AGENT_FIREWALL_POLICY_FILE |
bundled policies/default.yaml |
policy document |
AGENT_FIREWALL_AUDIT_LOG |
.agent_firewall/audit.jsonl |
audit log path |
AGENT_FIREWALL_ON_ERROR |
ask |
fail mode on error: ask / deny / allow |
AGENT_FIREWALL_PROJECT_ROOT |
cwd | project boundary for path checks |
AGENT_FIREWALL_ENV |
development |
environment label |
AGENT_FIREWALL_EMIT_ALLOW |
unset | set 1 to emit explicit allow |
Audit log
Append-only JSONL with a SHA-256 hash chain; audit verify detects truncation
or edits, and concurrent processes serialize appends via a lock file. Request
summaries are secret-scrubbed and raw tool input is never written verbatim. It
is tamper-evident, not tamper-proof — see
docs/limitations.md.
Development
python -m pytest # test suite (unit tests in tests/)
python scripts/smoke_test.py # end-to-end sanity check on synthetic inputs
ruff check . # lint
mypy # strict type-check
All test fixtures and smoke-test inputs use synthetic credentials and safe, non-executed command strings.
Project layout
src/agent_firewall/
engine.py core evaluation pipeline
authorization.py fail-closed identity/tool gate
normalize.py vendor payload -> NormalizedRequest
models.py typed domain models (pydantic)
config.py env-driven CoreConfig
detection/ command / filesystem / secrets / dlp / prompt-injection
risk/ deterministic additive scorer + weights
policies/ YAML schema, loader, evaluator
audit/ hash-chained JSONL writer + verifier
integrations/claude_code/ PreToolUse hook adapter
integrations/mcp/ MCP gateway server (optional [mcp] extra)
hooks/pre_tool_use.py thin stdin entry point for Claude Code
policies/default.yaml bundled policy set
docs/limitations.md threat model & known gaps
Contributing & security
Contributions are welcome — see CONTRIBUTING.md for the dev
setup and the quality gate to run before a PR. To report a vulnerability, use
GitHub private vulnerability reporting as described in
SECURITY.md (please don't file public issues for security bugs).
License
MIT.
Metadata
Release files for agent-firewall1 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_firewall1-0.1.0.tar.gz | 41.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_firewall1-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.9 kB
Release files / agent_firewall1-0.1.0.tar.gz
| Download URL | agent_firewall1-0.1.0.tar.gz |
|---|---|
| Size | 41.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6debd886e0f4074c272a9707685f2e2834a3e179c148993d3134c3882d5f8530
|
|
BLAKE2b-256 checksum How to use checksums |
2bdb77c1ceafce48d0ee080b83cf084bc73fd947b873d3566e33acd0ddd899a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency logRelease files / agent_firewall1-0.1.0-py3-none-any.whl
| Download URL | agent_firewall1-0.1.0-py3-none-any.whl |
|---|---|
| Size | 50.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6da98824206fa37c74fd850e37ba8fac8dfb5d4dac6ea0efe909a811dc577ffe
|
|
BLAKE2b-256 checksum How to use checksums |
679991acd797d9d259f2ab2e8e742ad28c144d5903e1fbca13da64dff20f41f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.
Transparency log