I built Airlock because I don't want an agent's mistake to become my incident. In Airlock the model only proposes actions. A deterministic policy engine decides allow or deny before anything runs. Python is parsed with ast against an allow-list of modules, attributes and file paths; shell is parsed with a lexer against allow-listed binaries and options. Unknown input is denied. Allowed code runs in a throwaway Docker container under gVisor (runsc) with network none, a read-only root filesystem, the job as uid 65534 without capabilities, and time, memory, CPU and process limits. A verifier checks the result, scans output for secrets and confirms the container was removed. Every decision, allowed or denied, gets a receipt: RFC 8785 canonical JSON, SHA-256, Ed25519 signature and a hash chain. The page verifies receipts in the browser with WebCrypto, and a tamper button shows a failed check. The demo opens with one button that replays a compromised agent, and has four tabs: the compromised agent (replay or live model), a real log-analysis task, an Arena where you type code yourself, and a verifier. In the replay, a scripted run shows what an agent that obeyed the injection would propose: the analysis step runs, and curl | sh, reading the environment and deleting input are denied before any container starts. The proposals are scripted; the gate, sandbox, verifier and receipts are real, and the receipts are marked as replay. The agent uses Vultr Serverless Inference (qwen3.8-27b) and everything runs on one Vultr Cloud Compute VM. The policy numbers hold on my test corpora only; the sandbox is the real boundary.
Category tags: