The Pydantic-based Firewall for MCP Servers. Stops hallucinated tool calls, validates schemas, and sandboxes dangerous operations.
Project description
The Open-Source Firewall for AI Agents
One decorator. Zero trust. Full control.
Test suite: 1,696 tests · Coverage: 82.66% · v0.5.6
Get Started in 30 Seconds · Why Airlock? · All Frameworks · Docs
┌────────────────────────────────────────────────────────────────┐
│ 🤖 AI Agent: "Let me help clean up disk space..." │
│ ↓ │
│ rm -rf / --no-preserve-root │
│ ↓ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 🛡️ AIRLOCK: BLOCKED │ │
│ │ │ │
│ │ Reason: Matches denied pattern 'rm_*' │ │
│ │ Policy: STRICT_POLICY │ │
│ │ Fix: Use approved cleanup tools only │ │
│ └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
🎯 30-Second Quickstart
pip install agent-airlock
from agent_airlock import Airlock
@Airlock()
def transfer_funds(account: str, amount: int) -> dict:
return {"status": "transferred", "amount": amount}
# LLM sends amount="500" (string) → BLOCKED with fix_hint
# LLM sends force=True (invented arg) → STRIPPED silently
# LLM sends amount=500 (correct) → EXECUTED safely
That's it. Your function now has ghost argument stripping, strict type validation, and self-healing errors.
🧠 The Problem No One Talks About
The Hype
|
The RealityLLMs hallucinate tool calls. Every. Single. Day.
|
Enterprise solutions exist: Prompt Security ($50K/year), Pangea (proxy your data), Cisco ("coming soon").
We built the open-source alternative. One decorator. No vendor lock-in. Your data never leaves your infrastructure.
✨ What You Get
|
Ghost Args Strip LLM-invented params |
Strict Types No silent coercion |
Self-Healing LLM-friendly errors |
E2B Sandbox Isolated execution |
RBAC Role-based access |
PII Mask Auto-redact secrets |
|
Network Guard Block data exfiltration |
Path Validation CVE-resistant traversal |
Circuit Breaker Fault tolerance |
OpenTelemetry Enterprise observability |
Cost Tracking Budget limits |
Vaccination Auto-secure frameworks |
📋 Table of Contents
Click to expand full navigation
🔥 Core Features
🔒 E2B Sandbox Execution
from agent_airlock import Airlock, STRICT_POLICY
@Airlock(sandbox=True, sandbox_required=True, policy=STRICT_POLICY)
def execute_code(code: str) -> str:
"""Runs in an E2B Firecracker MicroVM. Not on your machine."""
exec(code)
return "executed"
| Feature | Value |
|---|---|
| Boot time | ~125ms cold, <200ms warm |
| Isolation | Firecracker MicroVM |
| Fallback | sandbox_required=True blocks local execution |
Air-gapped / on-prem? DockerBackend is the supported alternative
— cap_drop=["ALL"], no-new-privileges, network_mode="none",
timeout enforced, opt-in pytest -m docker integration tests. See
docs/sandbox/docker.md.
📜 Security Policies
from agent_airlock import (
PERMISSIVE_POLICY, # Dev - no restrictions
STRICT_POLICY, # Prod - rate limited, agent ID required
READ_ONLY_POLICY, # Analytics - query only
BUSINESS_HOURS_POLICY, # Dangerous ops 9-5 only
)
# Or build your own:
from agent_airlock import SecurityPolicy
MY_POLICY = SecurityPolicy(
allowed_tools=["read_*", "query_*"],
denied_tools=["delete_*", "drop_*", "rm_*"],
rate_limits={"*": "1000/hour", "write_*": "100/hour"},
time_restrictions={"deploy_*": "09:00-17:00"},
)
Running an MCP server with STDIO transport? Also wire the Ox MCP STDIO sanitizer via
stdio_guard_ox_defaults()— it blocks the entire CVE-2026-30616 class (shell metacharacter injection, non-allowlisted binaries, Trojan-Source RTL overrides, and inline-code flags) beforesubprocess.Popen.
💰 Cost Control
A runaway agent can burn $500 in API costs before you notice.
from agent_airlock import Airlock, AirlockConfig
config = AirlockConfig(
max_output_chars=5000, # Truncate before token explosion
max_output_tokens=2000, # Hard limit on response size
)
@Airlock(config=config)
def query_logs(query: str) -> str:
return massive_log_query(query) # 10MB → 5KB
ROI: 10MB logs = ~2.5M tokens = $25/response. Truncated = ~1.25K tokens = $0.01. 99.96% savings.
🔐 PII & Secret Masking
config = AirlockConfig(
mask_pii=True, # SSN, credit cards, phones, emails
mask_secrets=True, # API keys, passwords, JWTs
)
@Airlock(config=config)
def get_user(user_id: str) -> dict:
return db.users.find_one({"id": user_id})
# LLM sees: {"name": "John", "ssn": "[REDACTED]", "api_key": "sk-...XXXX"}
12 PII types detected · 4 masking strategies · Zero data leakage
🌐 Network Airgap (V0.3.0)
Block data exfiltration during tool execution:
from agent_airlock import network_airgap, NO_NETWORK_POLICY
# Block ALL network access
with network_airgap(NO_NETWORK_POLICY):
result = untrusted_tool() # Any socket call → NetworkBlockedError
# Or allow specific hosts only
from agent_airlock import NetworkPolicy
INTERNAL_ONLY = NetworkPolicy(
allow_egress=True,
allowed_hosts=["api.internal.com", "*.company.local"],
allowed_ports=[443],
)
💉 Framework Vaccination (V0.3.0)
Secure existing code without changing a single line:
from agent_airlock import vaccinate, STRICT_POLICY
# Before: Your existing LangChain tools are unprotected
vaccinate("langchain", policy=STRICT_POLICY)
# After: ALL @tool decorators now include Airlock security
# No code changes required!
Supported: LangChain, OpenAI Agents SDK, PydanticAI, CrewAI
⚡ Circuit Breaker (V0.4.0)
Prevent cascading failures with fault tolerance:
from agent_airlock import CircuitBreaker, AGGRESSIVE_BREAKER
breaker = CircuitBreaker("external_api", config=AGGRESSIVE_BREAKER)
@breaker
def call_external_api(query: str) -> dict:
return external_service.query(query)
# After 5 failures → circuit OPENS → fast-fails for 30s
# Then HALF_OPEN → allows 1 test request → recovers or reopens
📈 OpenTelemetry Observability (V0.4.0)
Enterprise-grade monitoring:
from agent_airlock import configure_observability, observe
configure_observability(
service_name="my-agent",
otlp_endpoint="http://otel-collector:4317",
)
@observe(name="critical_operation")
def process_data(data: dict) -> dict:
# Automatic span creation, metrics, and audit logging
return transform(data)
🔌 Framework Compatibility
The Golden Rule:
@Airlockmust be closest to the function definition.
@framework_decorator # ← Framework sees secured function
@Airlock() # ← Security layer (innermost)
def my_function(): # ← Your code
LangChain / LangGraphfrom langchain_core.tools import tool
from agent_airlock import Airlock
@tool
@Airlock()
def search(query: str) -> str:
"""Search for information."""
return f"Results for: {query}"
|
OpenAI Agents SDKfrom agents import function_tool
from agent_airlock import Airlock
@function_tool
@Airlock()
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Weather in {city}: 22°C"
|
PydanticAIfrom pydantic_ai import Agent
from agent_airlock import Airlock
@Airlock()
def get_stock(symbol: str) -> str:
return f"Stock {symbol}: $150"
agent = Agent("openai:gpt-4o", tools=[get_stock])
|
CrewAIfrom crewai.tools import tool
from agent_airlock import Airlock
@tool
@Airlock()
def search_docs(query: str) -> str:
"""Search internal docs."""
return f"Found 5 docs for: {query}"
|
More frameworks: LlamaIndex, AutoGen, smolagents, Anthropic
LlamaIndex
from llama_index.core.tools import FunctionTool
from agent_airlock import Airlock
@Airlock()
def calculate(expression: str) -> int:
return eval(expression, {"__builtins__": {}})
calc_tool = FunctionTool.from_defaults(fn=calculate)
AutoGen
from autogen import ConversableAgent
from agent_airlock import Airlock
@Airlock()
def analyze_data(dataset: str) -> str:
return f"Analysis of {dataset}: mean=42.5"
assistant = ConversableAgent(name="analyst", llm_config={"model": "gpt-4o"})
assistant.register_for_llm()(analyze_data)
smolagents
from smolagents import tool
from agent_airlock import Airlock
@tool
@Airlock(sandbox=True)
def run_code(code: str) -> str:
"""Execute in E2B sandbox."""
exec(code)
return "Executed"
Anthropic (Direct API)
from agent_airlock import Airlock
@Airlock()
def get_weather(city: str) -> str:
return f"Weather in {city}: 22°C"
# Use in tool handler
def handle_tool_call(name, inputs):
if name == "get_weather":
return get_weather(**inputs) # Airlock validates
Complete Examples
| Framework | Example | Key Features |
|---|---|---|
| LangChain | langchain_integration.py |
@tool, AgentExecutor |
| LangGraph | langgraph_integration.py |
StateGraph, ToolNode |
| OpenAI Agents | openai_agents_sdk_integration.py |
Handoffs, manager pattern |
| PydanticAI | pydanticai_integration.py |
Dependencies, structured output |
| LlamaIndex | llamaindex_integration.py |
ReActAgent |
| CrewAI | crewai_integration.py |
Crews, roles |
| AutoGen | autogen_integration.py |
ConversableAgent |
| smolagents | smolagents_integration.py |
CodeAgent, E2B |
| Anthropic | anthropic_integration.py |
Direct API |
| Claude Agent SDK | anthropic_integration.py (Example 7) |
Agent SDK tools as in-process MCP servers |
⚡ FastMCP Integration
from fastmcp import FastMCP
from agent_airlock.mcp import secure_tool, STRICT_POLICY
mcp = FastMCP("production-server")
@secure_tool(mcp, policy=STRICT_POLICY)
def delete_user(user_id: str) -> dict:
"""One decorator: MCP registration + Airlock protection."""
return db.users.delete(user_id)
🏆 Why Not Enterprise Vendors?
| Prompt Security | Pangea | Agent-Airlock | |
|---|---|---|---|
| Pricing | $50K+/year | Enterprise | Free forever |
| Integration | Proxy gateway | Proxy gateway | One decorator |
| Self-Healing | ❌ | ❌ | ✅ |
| E2B Sandboxing | ❌ | ❌ | ✅ Native |
| Your Data | Their servers | Their servers | Never leaves you |
| Source Code | Closed | Closed | MIT Licensed |
We're not anti-enterprise. We're anti-gatekeeping. Security for AI agents shouldn't require a procurement process.
📦 Installation
# Core (validation + policies + sanitization)
pip install agent-airlock
# With E2B sandbox support
pip install agent-airlock[sandbox]
# With FastMCP integration
pip install agent-airlock[mcp]
# Everything
pip install agent-airlock[all]
# E2B key for sandbox execution
export E2B_API_KEY="your-key-here"
🛡️ OWASP Compliance
Agent-Airlock maps to the OWASP Top 10 for Agentic Applications (2026) — the agentic-era successor to the old LLM Top 10. Coverage is reported honestly: Full means the primitive ships and blocks the class in tests; Partial means agent-airlock covers the runtime leg but something upstream (client UI, IAM, training data) is out of scope; Monitor-only means we surface the signal but do not actually prevent the risk.
| Risk | Implemented in agent-airlock | Module / preset | Coverage |
|---|---|---|---|
| ASI01 Agent Goal Hijack | Pydantic strict validation + ghost-arg rejection + UnknownArgsMode.BLOCK |
validator, unknown_args, core |
Partial |
| ASI02 Tool Misuse and Exploitation | Deny-by-default SecurityPolicy, RBAC, rate limits, SafePath / SafeURL, Flowise Function()/eval token ban (CVE-2025-59528), MCPwn destructive-auth check (CVE-2026-33032) |
policy, safe_types, filesystem, network, policy_presets.flowise_cve_2025_59528_defaults, policy_presets.mcpwn_cve_2026_33032_defaults |
Full |
| ASI03 Identity and Privilege Abuse | AgentIdentity, MCPProxyGuard token-passthrough prevention, CredentialScope, OAuth-app audit (Vercel 2026-04-19) |
policy, mcp_proxy_guard, mcp_spec.oauth_audit, policy_presets.oauth_audit_vercel_2026_defaults |
Partial |
| ASI04 Agentic Supply Chain Vulnerabilities | Ox MCP STDIO sanitizer + CVE regression suite (10+ CVEs tracked) + session-snapshot integrity guard | mcp_spec.stdio_guard, mcp_spec.session_guard, policy_presets.stdio_guard_ox_defaults, tests/cves/ |
Partial |
| ASI05 Unexpected Code Execution (RCE) | E2B Firecracker sandbox, pluggable SandboxBackend, capability gating for PROCESS_SHELL, Flowise eval-token ban (CVE-2025-59528) |
sandbox, sandbox_backend, capabilities, policy_presets.flowise_cve_2025_59528_defaults |
Full |
| ASI06 Memory & Context Poisoning | AirlockContext contextvars isolation, ConversationConstraints budget caps, audit logging |
context, conversation, sanitizer |
Partial |
| ASI07 Insecure Inter-Agent Communication | A2A middleware Pydantic strict validation, method allow-lists | a2a |
Partial |
| ASI08 Cascading Failures | CircuitBreaker, RetryPolicy, token-bucket rate limits |
circuit_breaker, retry, policy |
Full |
| ASI09 Human-Agent Trust Exploitation | Honeypot deception, audit-log attribution, structured fix_hints |
honeypot, audit_otel |
Partial |
| ASI10 Rogue Agents | Audit telemetry + anomaly detector; no quarantine primitive | observability, anomaly |
Monitor-only |
MCP-specific mapping
The OWASP MCP Top 10 (2026 beta)
is covered end-to-end by the OWASP_MCP_TOP_10_2026 policy preset:
| MCP risk | Ships in agent-airlock |
|---|---|
| MCP01 Token Mismanagement | MCPProxyGuard rejects passthrough headers, enforces audience |
| MCP02 Excessive Permissions | SecurityPolicy + CredentialScope |
| MCP03 Tool Poisoning | ghost-arg rejection + SafePath/SafeURL |
| MCP04 Supply Chain | stdio_guard_ox_defaults() (Ox 2026-04-16 advisory) |
| MCP05 Command Injection | stdio_guard shell-metachar + deny-pattern rules |
| MCP07 Insufficient Authentication | OAuth 2.1 + PKCE S256 helpers in mcp_spec.oauth |
| MCP10 Context Oversharing | PII/secret sanitizer + workspace-scoped config |
Use it directly:
from agent_airlock import Airlock
from agent_airlock.policy_presets import owasp_mcp_top_10_2026_policy
@Airlock(policy=owasp_mcp_top_10_2026_policy())
def my_mcp_tool(...):
...
Ox Security STDIO advisory (2026-04-16, CVE-2026-30616): see
docs/cves/index.md#cve-2026-30616and thestdio_guard_ox_defaults()preset above. agent-airlock blocks 3 of 4 Ox attack classes at the runtime seam.
🏢 Used By
Agent-Airlock secures AI agent systems in production:
| Project | Use Case |
|---|---|
| FerrumDeck | AgentOps control plane — deny-by-default tool execution |
| Mnemo | MCP-native memory database — secure tool call validation |
Using Agent-Airlock in production? Open a PR to add your project!
📊 Performance
Test count and coverage are published by the TEST-BADGE block at the top of this file, regenerated from pytest on every release via
python scripts/update_test_badge.py. That block is the source of truth; this table tracks latency and surface area only.
| Metric | Value |
|---|---|
| Lines of Code | ~27,400 |
| Validation overhead | <50ms |
| Sandbox cold start | ~125ms |
| Sandbox warm pool | <200ms |
| Framework integrations | 10 |
| Core dependencies | 0 (Pydantic only) |
📖 Documentation
| Resource | Description |
|---|---|
| Examples | 9 framework integrations with copy-paste code |
| Security Guide | Production deployment checklist |
| API Reference | Every function, every parameter |
| Egress Bench | CVE fixture walker — every payload previously blocked stays blocked |
| OX MCP Supply-Chain preset | Umbrella for the 2026-04-20 OX dossier (10 CVEs) |
| DockerBackend | v0.5.1 hardening + known gaps |
Regulatory engagement
- Public comment draft — NIST AI RMF v2.0 Agentic-AI Security (window: 2026-04-18 → mid-June)
👤 About
Built by Sattyam Jain — AI infrastructure engineer.
This started as an internal tool after watching an agent hallucinate its way through a production database. Now it's yours.
🤝 Contributing
We review every PR within 48 hours.
git clone https://github.com/sattyamjjain/agent-airlock
cd agent-airlock
pip install -e ".[dev]"
pytest tests/ -v
- Bug? Open an issue
- Feature idea? Start a discussion
- Want to contribute? See open issues
💖 Support
If Agent-Airlock saved your production database:
- ⭐ Star this repo — Helps others discover it
- 🐛 Report bugs — Open an issue
- 📣 Spread the word — Tweet, blog, share
⭐ Star History
Sources: This README follows best practices from awesome-readme, Best-README-Template, and the GitHub Blog.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_airlock-0.5.6.tar.gz.
File metadata
- Download URL: agent_airlock-0.5.6.tar.gz
- Upload date:
- Size: 200.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f105f142b6b568bcf4df9b678cf1617d47c76308f6777b859023b8af26ceee17
|
|
| MD5 |
299b8e2bc0436d50225fac4945b6abba
|
|
| BLAKE2b-256 |
f2efe2820ea65df1b333a47f01f96a40faaa77622a975a441519430fd13b9b83
|
File details
Details for the file agent_airlock-0.5.6-py3-none-any.whl.
File metadata
- Download URL: agent_airlock-0.5.6-py3-none-any.whl
- Upload date:
- Size: 227.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c81e3f99193909c81b6330e707e0b1323154e69d5f125ba9600df3c6062791b
|
|
| MD5 |
9ba29f8b3a0b13efa840410ed338862e
|
|
| BLAKE2b-256 |
623ebf37d280eda0268db1787a237aa60bb594e0d2095b770bdf8ecf46b44a3f
|