Skip to main content

Agent-Airlock

A deny-by-default contract layer for AI agent tool calls

Strict argument validation, ghost-argument stripping, and self-healing retries — one decorator, any agent or MCP server. Pydantic-only core.

PyPI version Downloads CI Python 3.10+ License: Apache 2.0

Test suite: 4,512 tests · Coverage: 87.44% · v0.10.6
Coverage runs 4,500 of 4,512; the 12 excluded are 8 benchmark tests (not correctness tests) and 4 docker-marked (need a daemon — they run in CI's docker-sandbox job, against the image built from the Dockerfile at the repo root).

Quickstart · Benchmarks · Frameworks · Docs · How numbers are reported


The problem

An LLM decides which tool to call and what to pass it. Nothing checks the arguments before they reach your code.

# Your tool expects an int. The model sends a string, and invents a parameter.
transfer_funds(amount="500", to="alice", force=True)
#                     ^^^^^              ^^^^^^^^^^
#                     wrong type         never in your signature

Type coercion turns "500" into 500 and moves on. The invented force=True lands in **kwargs and silently changes behaviour. Neither is a model failure you can prompt away — it is a missing contract at the call boundary.

Quickstart

pip install "agent-airlock>=0.10.3"
from agent_airlock import Airlock

@Airlock()
def transfer_funds(amount: int, to: str) -> str:
    return f"Sent ${amount} to {to}"

That is the whole integration. Now:

The model sends What happens
amount="500" Blocked — Pydantic V2 strict mode, no coercion. Returns a structured error carrying fix_hints the model can retry against
force=True Stripped — a parameter that is not in your signature never reaches your function
amount=500, to="alice" Executes

A blocked call returns an AirlockResponse rather than raising, so the model gets a refusal it can act on instead of a traceback it cannot.

What it does

The decorator runs a fixed sequence of gates before your function and sanitises after it. Everything except validation is off by default.

Layer What it covers
Validate Pydantic V2 strict mode · ghost-argument stripping · self-healing fix_hints
Authorize RBAC · token-bucket rate limits · time windows · per-model-tier cost budgets · capability gating
Isolate Filesystem path validation · network egress control · sandboxed execution (E2B, Modal, Docker, local)
Sanitize PII and secret masking, including opt-in Indic PII · output truncation · JSON-Lines audit log
MCP guards Per-CVE guards for stdio injection, OAuth, DNS rebinding, SSRF, eval-RCE, WebSocket origin and task lifecycle — tracking MCP spec revision 2026-07-28

Full reference on the documentation site.

Benchmarks

Every row is one command you can run. Dates are when the number was last actually produced, not when the row was last edited — check_benchmark_freshness.py fails the release if any row drifts past 30 days.

Benchmark Result Reproduce
Cross-tool block-rate · 210 tool calls 100% blocked · 0% false-positive · p50 ~2µs · 6 of 10 OWASP ASI slots measured; ASI07–ASI10 are n=0 python -m benchmarks.blockrate · re-run 2026-09-16 · results
sandbox=True dispatch · contract parity 4/4 annotated-contract probes refused on the sandbox path (0/4 before v0.10.6) · 204/204 verdicts agree with the local path. Isolation-backend execution not run here: no E2B or Docker in the runner, reported as not-run rather than folded in python -m benchmarks.blockrate · re-run 2026-09-16 · results
Least-privilege · ToolPrivBench, 100 scenarios 100% over-privileged blocked · 100% low-privileged allowed · OPUR 100% → 0% python -m benchmarks.toolprivbench · re-run 2026-09-08 · results
Adaptive attacker · AgentDojo, all 4 suites 86.0% of injection→target tool-calls blocked (524/609, deterministic bound). Model-in-the-loop ASR 45% → 10%, but that is one model family on a 60-pair subset python -m benchmarks.agentdojo.run · re-run 2026-09-08 · results
vs. native MCP gateway · 12 malformed payloads airlock 12/12 blocked · Docker MCP Gateway 0/12 · 0% false-positive on both python -m benchmarks.vs_gateway · re-measured live 2026-09-12 · results
Prompt injection across agent harnesses A null result, published as one. claude-code and codex each acted on the planted script 0/36 — but they ignored the benign twin just as completely, so this is indifference to the channel, not detection python -m benchmarks.harness_injection · last verified 2026-08-26 · results
MCP spec conformance · @modelcontextprotocol/conformance Run against the wire-path validators, outcome published in full. Not a full MCP server/client conformance pass — airlock is a request validator, not a server, so it does not claim one benchmarks/mcp_conformance/RESULTS.md · re-run 2026-09-08

Summary and method: BENCHMARK.md.

Where this sits

Airlock is in-process. It is not a proxy, a gateway or a sidecar — it runs inside the process that executes the tool, which is the only place the real Python arguments exist.

That makes it complementary to the layers around it, not a replacement for them. A gateway authenticates identity and transport and sandboxes the server; it does not validate the tool call's argument contract. Measured live against a Docker MCP Gateway on 12 malformed payloads, the gateway forwarded 12/12 that airlock blocks.

Framework support

Both paths use the same @Airlock() decorator. Adapter-shipped means a dedicated module under src/agent_airlock/integrations/ handles framework-specific glue — signature preservation, tool-registry rewrites, request-shape adapters. Example-only means the decorator works out of the box with no adapter.

Adapter-shipped (12): LangChain (integrations/langchain.py), LangGraph (integrations/langgraph_toolnode_compat.py), OpenAI Agents SDK (integrations/openai_guardrails.py), Anthropic Messages API (integrations/anthropic.py), Anthropic Claude Agent SDK (integrations/anthropic_claude_agent_sdk.py, v0.6.1+), smolagents (integrations/smolagents_wrapper.py), Gemini 3 Agent Mode (integrations/gemini3_tool_shape_adapter.py), GPT-5.5 (integrations/gpt5_5_tool_shape_adapter.py), PydanticAI (integrations/pydantic_ai.py, v0.7.1+), CrewAI (integrations/crewai.py, v0.7.2+), Google ADK (integrations/google_adk.py, v0.9.0+), FastMCP (agent_airlock/mcp/).

Example-only (2): AutoGen, LlamaIndex — decorator-compatible without an adapter.

Every framework: adapter, doc and runnable example

Complete Examples

Framework Path Surface
LangChain adapter · example @tool, AgentExecutor
LangGraph adapter · example StateGraph, ToolNode
OpenAI Agents adapter · example Handoffs, manager pattern
Anthropic API adapter · example Direct Messages API
Claude Agent SDK adapter · doc wrap_agent(agent, policy=...)
smolagents adapter · example CodeAgent, E2B
Gemini 3 adapter function_call carrier + thought_signature redaction
GPT-5.5 adapter gpt_5_5_agent_defaults preset
FastMCP adapter · example @secure_tool decorator
PydanticAI adapter · doc · example wrap_agent(agent, policy=...) + output_validate hook
CrewAI adapter · doc · example wrap_crew(crew, policy=...) + task-level tool overrides
Google ADK adapter · doc · example wrap_agent(agent, policy) + tool_context relaxation
LlamaIndex example only ReActAgent
AutoGen example only ConversableAgent

Decorator-ordering rules per framework: docs/COMPATIBILITY.md.

Security coverage

Mapped against the OWASP Agentic Top-10 (2026). Partial means airlock covers the runtime leg and something upstream is out of scope. Every label is justified per row in docs/owasp-agentic-2026-coverage.md, which is generated from a YAML source and byte-diffed in CI.

Risk Primary controls Coverage
ASI01 Agent Goal Hijack Sequence guard, action-contradiction gate, tool-output trust guard Partial
ASI02 Tool Misuse and Exploitation Strict validation, ghost-arg stripping, SafePath / SafeURL, capability gating Full
ASI03 Identity and Privilege Abuse RBAC, signed agent identity, capability-union boundary, privilege right-sizing Partial
ASI04 Agentic Supply Chain Vulnerabilities Description and manifest pinning, schema $ref guard, tool-definition pin, attested admission, and 45 CVE/advisory regression tests in tests/cves/ (the 36 distinct CVEs they cover are published in the generated catalog) Partial
ASI05 Unexpected Code Execution (RCE) Eval-RCE guards, sandboxed execution, stdio command-injection guards Full
ASI06 Memory & Context Poisoning Auto-memory provenance, cross-tenant isolation, conversation tracking Partial
ASI07 Insecure Inter-Agent Communication A2A guard, MCP proxy guard, transport validation Partial
ASI08 Cascading Failures Circuit breaker, retry policy, amplification budget Full
ASI09 Human-Agent Trust Exploitation Human-oversight decorator, elicitation guard, honeypot deception Partial
ASI10 Rogue Agents Audit telemetry, anomaly detector, kill switch — no quarantine primitive Monitor-only

MCP-specific mapping

Against the MCP Top-10. Evidence is compressed here; each row's full justification is in docs/owasp-agentic-2026-coverage.md.

Risk Primary controls Coverage
MCP01 Token Mismanagement & Secret Exposure MCPProxyGuard rejects passthrough headers and enforces audience; sanitizer masks secrets in tool output Partial
MCP02 Privilege Escalation via Scope Creep require_agent_id preset, capability gating, CredentialScope, runtime capability-union deny at grant time Full
MCP03 Tool Poisoning Ghost-arg rejection, SafePath / SafeURL, mcp_description_manifest_guard, install_* deny Full
MCP04 Software Supply Chain Attacks & Dependency Tampering stdio_guard_ox_defaults() (Ox 2026-04-16 advisory), download_plugin_* / fetch_plugin_* deny Full
MCP05 Command Injection & Execution stdio_guard shell-metachar and deny-pattern rules, exec_* / run_* / system_* deny, sandbox for DANGEROUS Full
MCP06 Intent Flow Subversion ToolOutputTrustGuard envelopes injected-instruction output; @requires_human_oversight gates high-value actions Partial
MCP07 Insufficient Authentication & Authorization OAuth 2.1 + PKCE S256 helpers, iss mix-up validation, header/body routing integrity, unsigned-_meta trust boundary, step-up scope guard, Tasks lifecycle and admission guards. Transport-level auth remains server-side Partial
MCP08 Lack of Audit and Telemetry JSON-Lines audit log, OpenTelemetry export, spans and metrics Full
MCP09 Shadow MCP Servers Attested tool-server admission, LAN unauthenticated-MCP guard Partial
MCP10 Context Injection & Over-Sharing PII and secret sanitizer, workspace-scoped config, ToolOutputTrustGuard untrusted-data envelope Full

Use it directly via the presets named above, or the per-CVE catalogue at docs/cves/index.md.

CLI

One CLI: airlock <command> (unified dispatcher, full command set since v0.8.56)

airlock scan-tools ./tools.json     # static contract check on tool declarations
airlock doctor                      # environment and config diagnosis
airlock explain --unused-scopes     # diff granted privilege against used
airlock attest receipt emit ...     # signed evidence that a run was gated
airlock policy compile "..."        # English to typed policy (needs an LLM backend)
airlock kill-switch trigger         # HMAC-signed fleet freeze

Per-command documentation: CLI reference.

Performance

Metric Value Detail
Validation overhead ~2µs p50 per decision deterministic, in-process
Framework integrations 14 see above
Core dependencies 0 beyond the Pydantic foundation; everything else is an opt-in extra

How numbers are reported here

This project holds itself to a rule worth stating plainly: a claim in this README is gated by a test, or it is not made.

  • Counts — tests, CVEs, adapters — are cross-checked against the tree by tests/test_numeric_claim_parity.py and siblings. A number that drifts fails the build.
  • Benchmark dates are enforced. A row older than 30 days blocks a release.
  • Null results are published. The prompt-injection row above found nothing and says so, in the same table as the wins.
  • Competitor numbers are never fabricated. Where an incumbent is cited it is from their published scope and marked not re-run; where a comparison was run live, it says so.
  • Where no head-to-head exists, that is recorded rather than implied — see Prior art, including arXiv:2608.18351, where the honest claim is complementarity and not superiority.

Known gaps and their status: ROADMAP.md.

Documentation

Documentation site Guides, API reference, CLI, integrations
BENCHMARK.md Benchmark summary and method
docs/cves/index.md Generated CVE catalogue
ROADMAP.md What is not done, and why
PRIOR_ART.md External research this rests on
CHANGELOG.md Release history
AGENTS.md Contributor contract

Contributing

Read AGENTS.md first — it is the load-bearing contributor contract — then CONTRIBUTING.md.

pip install -e ".[dev]"
make test lint

Every feat: needs a regression test. Every CVE fixture needs a primary-source URL in the commit message. Claims need gates.

Security

Report vulnerabilities via SECURITY.md. Please do not open a public issue for an unpatched vulnerability.

License

Apache-2.0. Relicensed from MIT on 2026-09-06 to add an explicit patent grant. Citation metadata: CITATION.cff.


If this is useful, a ⭐ helps other people find it.

Report a bug · Request a feature · Discussions

Release files for agent-airlock 0.10.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for agent-airlock 0.10.6
File Size Uploaded
agent_airlock-0.10.6.tar.gz 654.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for agent-airlock 0.10.6
File Interpreter ABI Platform
agent_airlock-0.10.6-py3-none-any.whl Python 3 none any Details

Total release size: 1.4 MB

Release files / agent_airlock-0.10.6.tar.gz

Download URL agent_airlock-0.10.6.tar.gz
Size 654.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e3ef73bc9e4d40397b0e667028157b28bd71c880ea260f6f5f91ed8810534738
BLAKE2b-256 checksum
How to use checksums
9fe5c8adf873bc7807e58b66e822bdb388ee4ba49709893e25316139ef6e5c81
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / agent_airlock-0.10.6-py3-none-any.whl

Download URL agent_airlock-0.10.6-py3-none-any.whl
Size 782.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e276833b20e3261ecb7e6bf76c2a911e3844d4a0f44217e6696e3377f1d6ebd5
BLAKE2b-256 checksum
How to use checksums
feab29194310bbfbc09caaf68250cbfc0b0b5147d422a6f907148bdaee4c7d06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.10.8

2 release files

0.10.7

2 release files

This release

0.10.6 This release

2 release files

0.10.5

2 release files

0.10.4

2 release files

0.10.3

2 release files

0.10.2

2 release files

0.10.1

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.83

2 release files

0.8.82

2 release files

0.8.81

2 release files

0.8.80

2 release files

0.8.79

2 release files

0.8.78

2 release files

0.8.77

2 release files

0.8.76

2 release files

0.8.75

2 release files

0.8.74

2 release files

0.8.73

2 release files

0.8.72

2 release files

0.8.71

2 release files

0.8.70

2 release files

0.8.69

2 release files

0.8.60

2 release files

0.8.59

2 release files

0.8.58

2 release files

0.8.57

2 release files

0.8.56

2 release files

0.8.55

2 release files

0.8.54

2 release files

0.8.53

2 release files

0.8.52

2 release files

0.8.51

2 release files

0.8.50

2 release files

0.8.49

2 release files

0.8.48

2 release files

0.8.47

2 release files

0.8.46

2 release files

0.8.39

2 release files

0.8.38

2 release files

0.8.37

2 release files

0.8.36

2 release files

0.8.35

2 release files

0.8.34

2 release files

0.8.33

2 release files

0.8.32

2 release files

0.8.31

2 release files

0.8.30

2 release files

0.8.29

2 release files

0.8.28

2 release files

0.8.27

2 release files

0.8.26

2 release files

0.8.25

2 release files

0.8.24

2 release files

0.8.23

2 release files

0.8.22

2 release files

0.8.9

2 release files

0.8.8

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.6

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.9

2 release files

0.5.8

2 release files

0.5.7

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.2.0

2 release files

0.1.5

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page