Interlock: Proving a secret moved, instead of guessing that it might

yashwxnth2 pts0 comments

Interlock: catching MCP exfiltration at runtime, and being honest about what that means | Yashwanth Reddy Mali

Open to work<br>Backend engineer.<br>Platform, authorization,<br>and systems work.

Bay Area or remote.

25 July 2026<br>Interlock: catching MCP exfiltration at runtime, and being honest about what that means

Every MCP security tool I could find scans tool definitions before an agent is<br>allowed to use them. None of them can see the attack that actually matters in production:<br>a sequence of individually-authorized tool calls that chains into an exfiltration<br>pipeline.

Read a ticket. Follow the instruction hidden in the ticket body. Send a message.

Three approved calls. One breach. No individual call is anomalous.

Simon Willison named the shape. The lethal trifecta : access to private<br>data, exposure to untrusted content, and the ability to communicate externally. Any one<br>leg is safe. All three live in one session is how data walks out. The mid-2025<br>Supabase/Cursor breach was exactly this: privileged data access, attacker-supplied input,<br>an external channel.

Static scanners run before the session. The trifecta assembles during it. That gap is<br>where Interlock lives.

Won't better models just stop falling for this?

Sometimes. Probably. For a while.

That is the bet I did not want to build on. NIST's adversarial ML taxonomy (AI<br>100-2e2025) is blunt about the state of it: current mitigations cannot fully prevent<br>these attacks, and there is no foolproof defense available today. Model-level injection<br>resistance is a probability, and it decays the second someone finds a phrasing the<br>training didn't cover.

So I assumed the injection already won, and built for the step after it: catching the<br>secret on its way out.

That is the real argument for stacking, and it isn't just "defense in depth" as a<br>slogan. The two defenses fail independently. Injection resistance is a<br>property of training data. Exfil detection is a property of a byte comparison inside a<br>proxy. A phrasing clever enough to defeat the first has no purchase on the second,<br>because the second never reads the prompt. It reads the outbound arguments.

Which is why Interlock is model-agnostic on purpose. It sits between the agent and its<br>MCP servers, so it does not care whether that is Claude, GPT, or something someone wired<br>up locally at 2am. It watches what the agent does, not how the agent thinks. The model<br>can be as smart as it wants. Interlock is downstream of the reasoning.

Approach

Two observation planes, one correlation engine.

Agent

MCP Proxy

MCP serversuntrusted

InterceptedEvent

TCP, bypasses proxy

Attacker

Correlation Engine

→ Decision, enforced back at the proxy

→ Evidence, written to the sink

SyscallEvent

eBPF Sensor

Interlock's own path<br>untrusted / adversarial

Plane 1: a protocol-aware MCP proxy (Go). Not a byte pipe. It terminates<br>initialize, tools/list, and ping itself, spawns<br>every configured server as a child, and builds a tool-name to server routing table. The<br>agent sees one endpoint.

Plane 2: an eBPF sensor. Tracepoints on connect,<br>write, sendto, openat, scoped to the proxy's PID<br>subtree via a BPF hash map. This exists because a poisoned server does not have to use<br>the MCP channel to exfiltrate. It can just open a socket. The proxy is blind to that. The<br>kernel is not.

The engine owns one state machine per session. Three legs, lit by events<br>from either plane, correlated by PID and a monotonic timestamp.

The design decision everything else hangs on: verdict and action are separate<br>dimensions.

Verdict is what was concluded. Action is what was done about it. They are not the same<br>axis, and collapsing them is how security tools get uninstalled.

VerdictMeansHard enforcement

EXFIL (0.95)<br>A registered tainted value appears in the sink args or egress payload<br>Yes, blocked or contained

SUSPICIOUS (0.60)<br>All three legs lit, and the sink shares a long byte substring with untrusted content<br>No, evidence only

EXFIL is the bar for we proved a secret moved.<br>SUSPICIOUS is this session has the shape of risk. Only the first one<br>is allowed to break anything.

Implementation

Hold-before-forward. Enforcement hooks at the exact point where the<br>proxy has parsed a tools/call, extracted the tool name and args, and<br>resolved the target server. The engine evaluates there. On block, the frame is never<br>written to the child's stdin. The proxy synthesizes a JSON-RPC error using the same<br>response-synthesis path it already uses for tools/list. The agent gets a<br>legible failure instead of a hang.

Proof is byte overlap, not model judgment. When a tool tagged<br>sensitive_source returns data, the engine extracts candidate secrets and<br>precomputes canonical encodings: literal, base64, hex, URL-encoding, reversal, closed<br>depth-2 nests, gzip_base64. At sink time it scans the args for any of them.<br>On a miss it tries same-call JSON string reassembly, then a bounded recursive decoder<br>(base64/hex, depth 3 or less). A session-level fragment buffer closes cross-call...

proxy interlock agent tool data session

Related Articles