Skip to content
T threat.cafe

· Priya Venkatraman (editorial persona) · Enforcement architecture · on threat.cafe

Lethal trifecta audit: a worksheet to find agent setups that mix private data, untrusted content and egress

An agent setup can leak your data when one session combines three things: access to private data, exposure to content an outsider can write, and a way to send data out. Simon Willison named this the lethal trifecta in June 2025 and wrote that "the only way to stay safe there is to avoid that lethal trifecta combination entirely." Reviewing each MCP server or skill on its own misses the risk, because no single tool has all three legs. The worksheet below audits whole configurations, one session profile at a time, and marks which leg you can break most cheaply.

The question you are actually asking

You are adding a connector to an agent that already reads your repository or your inbox. The connector looks harmless. Your real question is whether the full set of tools in that session now adds up to a leak.

That question has a yes or no answer for each session profile. Most teams have never written the answer down.

The direct answer

List every tool the session can call. Tag each tool with the legs it supplies. If all three legs appear anywhere in the same session, the configuration is exposed. Fix it by removing one leg from that session, not by adding a warning to the prompt.

The mechanism, layer by layer

Leg 1: private data. Anything the agent can read that you would not publish: source code, .env files, email, tickets, customer records.

Leg 2: untrusted content. Anything the agent reads that someone outside your team could have written: a web page, an incoming email, a GitHub issue, a third-party README, a skill's instructions. In plain English, it is the input channel for an attacker's instructions.

Leg 3: outbound communication. Any way for data to leave. Willison lists the obvious one, a tool that makes web requests, and the less obvious ones: loading an image or offering a link for a user to click. Either can carry stolen data in its URL.

The catch is that leg 3 has more doors than "network access." Anthropic's Skills for enterprise guidance tells reviewers to look for instructions that read sensitive data and then send or encode it for external transmission, "including through Claude's conversational responses." It also tells them to "consider the combined risk when a Skill uses both file-read and network tools together." A tool that posts a comment to a public pull request is leg 3. So is a tool that sends email.

Why the combination matters: the attacker writes instructions into leg 2. The model cannot reliably tell those instructions apart from yours. It then reads leg 1 and writes the result to leg 3. Each tool behaved as designed. The leak lives in the arrangement.

Willison also notes that MCP "encourages users to mix and match tools from different sources." That is what makes the combination easy to assemble by accident.

A concrete worked example

Illustrative example: a team runs a coding agent with this session profile.

Tool                         Leg 1 private   Leg 2 untrusted   Leg 3 outbound
---------------------------  -------------   ---------------   --------------
Read / Edit (repo files)     YES             no                no
GitHub MCP (issues, PRs)     YES (private    YES (anyone can   YES (comments,
                             repos)          open an issue)    PRs on public
                                                               repos)
Web fetch                    no              YES               YES (URL in
                                                               request)
Bash with npm, curl          YES (reads      YES (package      YES (any host
                             ~/.npmrc etc)   READMEs, output)  allowed)
---------------------------  -------------   ---------------   --------------
Session total                YES             YES               YES  -> EXPOSED

The GitHub MCP server alone supplies all three legs when it can see both private and public repositories. Willison's post lists GitHub's official MCP server among products that had such exfiltration problems reported.

Now break one leg and recount. Option A: give the GitHub MCP server a token scoped to the private repositories only and remove web fetch. Leg 2 shrinks to issues that people with private-repo access can write. Option B: keep the tools, but turn on the agent's sandbox with an outbound allowlist of the package registry only. Leg 3 shrinks for Bash, but not for the GitHub tool, which can still comment. In this example, Option A breaks the combination and Option B does not.

The audit worksheet

Copy this once per session profile: each distinct combination of agent, settings and connected servers that people actually run.

LETHAL TRIFECTA AUDIT                    profile: __________  date: ______
Agent + version: ____________   Settings source: user / project / managed

STEP 1  List every tool, server and skill in the session.
STEP 2  Mark each leg. When unsure, mark YES.

Tool / server / skill     L1 private   L2 untrusted   L3 outbound   Notes
-----------------------   ----------   ------------   -----------   ---------
_______________________   [ ]          [ ]            [ ]
_______________________   [ ]          [ ]            [ ]
_______________________   [ ]          [ ]            [ ]
_______________________   [ ]          [ ]            [ ]

STEP 3  Session has all three legs?   [ ] no -> record and stop
                                      [ ] yes -> STEP 4

STEP 4  Pick the cheapest leg to break (see options). Write the change:
        ____________________________________________________________

STEP 5  Re-mark the table after the change. All three still present?
        [ ] no -> done   [ ] yes -> split into two session profiles

Owner: __________   Re-audit when any tool, scope or server changes.

Leg-breaking options, roughly cheapest first

  1. Split the session. Run research that reads untrusted content in one profile and work on private code in another. Nothing crosses unless a person carries it. This costs some convenience and no engineering.
  2. Narrow a token. Scope tokens so a tool sees only private or only public resources, not both. For remote MCP servers, Claude Code supports pinning OAuth scopes with oauth.scopes, per its MCP documentation.
  3. Restrict outbound hosts. Claude Code's sandbox routes shell traffic through a proxy that checks each host against an allowlist that starts empty. It warns that broad domains such as github.com "can create paths for data exfiltration," and that the sandbox covers shell commands only, not MCP servers or the built-in web tools.
  4. Block reads of secrets. Deny the credential files and variables the session does not need, so leg 1 holds less.
  5. Put a person on the outbound step. Require approval for actions that publish: posting comments, sending email, pushing to public repositories. Use this for the few actions that remain, not as the main control.

How long the audit takes

Most of the time goes into step 1, not the marking. Teams rarely have a list of which servers and skills each person's agent loads, so the first audit doubles as an inventory.

Illustrative example: a team with 5 session profiles averaging 8 tools each has 40 rows to mark. At a minute or two per row for someone who knows the tools, that is roughly an hour for the first pass. Later passes only touch rows that changed.

Three habits keep it short:

  • Audit profiles, not people. If ten developers run the same managed configuration, that is one worksheet.
  • Mark from documentation first. Read what each server says it can reach, mark conservatively, and only test the rows where the answer decides the outcome.
  • Start with the top five. The profiles with the most private data in leg 1 are where a break matters most.

Where the simple model stops being true

Leg 3 is never fully closed while a person reads the agent's output, because the response itself is a channel, as Anthropic's checklist notes. The worksheet treats that as acceptable when the reader is the session's owner. It is not acceptable when output flows automatically somewhere public.

Legs are also not binary. "Untrusted" covers a stranger's issue and a colleague's typo with very different odds. Marking YES when unsure keeps the audit conservative. If every profile comes back exposed, rank them by how much private data leg 1 reaches and fix the biggest first.

Finally, the audit finds structural exposure. It does not show that anyone has attacked you.

Decision checklist

  • Have you written down every session profile people actually run, including CI jobs?
  • Does any single tool supply all three legs on its own? Fix those first.
  • After your change, did you re-mark the table rather than assume?
  • Is the audit owner named, with a trigger to re-run it when tools change?

A known-bad check on what enters leg 2 complements the audit; the threat.cafe board lists documented malicious skills and servers you can rule out before they join a session.

Sources

#lethal-trifecta #prompt-injection #mcp #data-exfiltration #audit

All posts