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.
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 |
📋 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 |
📜 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"},
)
💰 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
🔌 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 |
⚡ 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 mitigates the OWASP Top 10 for LLMs (2025):
| OWASP Risk | Mitigation |
|---|---|
| LLM01: Prompt Injection | Strict type validation blocks injected payloads |
| LLM05: Improper Output Handling | PII/secret masking sanitizes outputs |
| LLM06: Excessive Agency | Rate limits + RBAC prevent runaway agents |
| LLM09: Misinformation | Ghost argument rejection blocks hallucinated params |
📊 Performance
| Metric | Value |
|---|---|
| Tests | 629 passing |
| Coverage | 86% (80% enforced in CI) |
| Validation overhead | <50ms |
| Sandbox cold start | ~125ms |
| Sandbox warm pool | <200ms |
| Framework integrations | 9 |
| 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 |
👤 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
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.1.5.tar.gz.
File metadata
- Download URL: agent_airlock-0.1.5.tar.gz
- Upload date:
- Size: 45.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
835ad4f94ea724de58c3cab7d16c0299bf0d4e13bf461195fa2b051726a8c5b0
|
|
| MD5 |
23366b15091f81131b4490d329f6c890
|
|
| BLAKE2b-256 |
bdf78b0e36cb3a62dfbeff6112be4dd8834153e7c386fdc728f24cc5e9fee6d6
|
File details
Details for the file agent_airlock-0.1.5-py3-none-any.whl.
File metadata
- Download URL: agent_airlock-0.1.5-py3-none-any.whl
- Upload date:
- Size: 53.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
40cf31fe7a0c2020953dbdb3c1d8776c0ced6c3e0a04c36a606e09bba40d2d4b
|
|
| MD5 |
45c2072fbd98c1e70394f14308530098
|
|
| BLAKE2b-256 |
54ef7738fe2199b73fb103c9c3124da307547efe5e839b5b00bfa7fe1b5d95bd
|