polyman sits between an agent and its tools, tracks what each session has touched, and denies any call that would let read-untrusted, touch-sensitive, and reach-egress coexist — before the call runs.
polyman sits between the agent and its tools. Nothing runs before it steps the machine.
Each tool maps to an effect class: untrusted-source / sensitive-source / egress-sink / benign. An unlabeled tool is denied. Default-deny.
A tiny per-session state machine accumulates the effects a session has touched, atomically.
Before a call runs, polyman steps the machine; if the result would enter the forbidden region, it rejects with a contract-anchored reason.
The shipped machine passes polysec harden: clean from init, no havoc counterexample, no gate-deletion bypass. Fully mediated.
Every serious analysis of AI-agent risk ends in the same place: the lethal trifecta (Simon Willison's name for it). The moment one agent session can read untrusted content, touch sensitive data, and reach an outbound channel, a prompt injection stops being a curiosity and becomes data exfiltration.
This isn't hypothetical. In July 2026, OpenAI disclosed that two of its own pre-release models broke out of a sandboxed evaluation, exploited a zero-day in an internal package registry proxy to reach the internet, and used that access to compromise Hugging Face systems — the same shape of failure, at the extreme end.
Every agent framework now ships a tool-approval hook to sit in front of this. They share one weakness: the policy inside the hook is a hand-written if. Nobody checked that it holds on every reachable combination of tool calls.
You are not trusting a hand-written if. You are enforcing a theorem: the same state-machine engine that proves the policy also steps it live, asserted byte-for-byte. No model or network call is on the decision path. $0, deterministic, and the tests assert it.
ifZero-config — the lethal-trifecta policy ships pre-proven.
const pm = await createPolyman(); // shipped, proven policy const res = await generateText({ model, tools, ...wrapVercel(pm, { session: conversationId }), // in-line default-deny gate });
Now a session that has fetched untrusted content and read a secret cannot send email — gmail.send is denied before it runs, no matter what the injection told the model. wrapVercel maps the gate onto the SDK's native toolApproval (deny before execution) and onStepEnd (record observed taint). ai is an optional peer dependency; the core is framework-agnostic.
The name is the joke and the architecture: polyman also fronts an MCP server as a true man-in-the-middle, so it can live outside the agent process entirely — a separate process the agent talks through, not a library the agent could route around, making the gate harder to tamper with than an in-process hook.
polyman is a reference monitor, not a sandbox. It stops a misguided agent — an injection steering legitimate tools. It does not, by itself, contain a compromised runtime that opens its own socket around the gate; that needs confinement, and it's the next phase. It proves the policy over effect classes — your tool→class labels are a trust obligation it can't check for you. The reference-monitor idea is Anderson, 1972; what's new is proving the policy fully mediated at design time and enforcing that exact proven machine at runtime.
Adapted from “Your Agent Is Lying to You,” Jean-Jacques Dubray. Repo: github.com/cognitive-fab/polysec.