Skip to content

+ Intertrace Threat ResearchTLP:CLEAR7 sources

Threat research9 min read

Cross-tool data laundering: when every call is allowed and the export is not

An agent can read restricted data, rewrite it and post it somewhere broader using only permitted tools. Seven beliefs that let this through, what public research and one disclosed case show instead, and the session labels, audience checks and canary tests that catch it.

How attacks on AI agents work in practice, from public incidents and our own test corpora, and the controls that stop them.

October 11, 2026 · 9 min read

Data ExfiltrationTool ChainsInformation Flow ControlMCP
Contents
  1. 01Myth: if every call is authorized, the session is
  2. 02Myth: a stricter permission review would have caught it
  3. 03Myth: data-loss checks on tool arguments will catch the data
  4. 04Myth: agents rarely get redirected this way
  5. 05Myth: flow tracking is a research problem
  6. 06Myth: you know where data went because you know which tool wrote it
  7. 07Myth: a refusal in the transcript means nothing leaked

The post-incident review usually goes the same way. Someone pulls the agent's permissions, and every one is justified: it reads customer records to answer support questions, it summarizes because that is the job, and it files issues because engineering asked for it. The access review passes. Yet a customer's data now sits in an issue several hundred people can read, and nobody granted that.

We call what happened in between data laundering: data loses its security context as it passes through a transformation, so a sensitive record comes out the other side looking like ordinary text with no owner and no audience restriction. The term is ours and names a failure mode, not a new exploit family. Our position is that teams keep missing it because of a handful of comfortable beliefs about per-call authorization, and that the fix is a flow control, accepted with its over-tainting cost, rather than harder inspection of each call.

Myth: if every call is authorized, the session is

Reality: in May 2025, Invariant Labs described an attack on agents using the GitHub MCP server [1]. An attacker files an issue in a public repository. When the owner asks their agent to look at open issues, the agent reads the injected instructions, pulls data from the owner's private repositories into its context, and publishes it in a pull request on the public repository, where the attacker can read it. Invariant demonstrated this with Claude 4 Opus in Claude Desktop and noted that many users set tool confirmations to Always Allow [1].

Every step was a call the agent was permitted to make with the user's own token. Invariant was explicit that this is not a flaw in the GitHub MCP server code but an architectural issue to be addressed at the agent-system level, and called the pattern a toxic agent flow [1]. Per-call authorization asks one question: may this principal invoke this tool with these arguments? It has no slot for where the arguments came from. A create-issue call whose body the user typed and one assembled from a restricted record look identical at the moment of the call. Willison's lethal trifecta says the same at session level: private data, untrusted content and an external channel together are dangerous even when each is reasonable alone [3].

Allowed calls, unauthorized flowFig. 1
CALL BY CALLRead pay runget_payrun(customer)ALLOWEDRewritemodel builds a tableALLOWEDFile issuecreate_issue(all-staff)ALLOWEDAS A FLOWRestricted recordaudience: the case teamUNAUTHORIZED FLOW · NO ONE DECIDEDAll-staff trackeraudience: all staffthe violation exists only in the path from source to sink, so only a check that sees the session can catch it

Viewed call by call, a read, a rewrite and a post each pass. Viewed as a flow, restricted data has moved to a broader audience with no one deciding that it should.

Myth: a stricter permission review would have caught it

Reality: the permissions were the right ones. OWASP's Excessive Agency entry names the root causes as excessive functionality, permissions and autonomy, and its example is a composition: an email assistant meant to summarize mail also has a send capability, so an injected message makes it search the inbox and forward what it finds [2]. The fixes OWASP recommends, a read-only scope, a person reviewing every sent message, and authorization enforced in downstream systems rather than by the model, work by breaking the chain, not by inspecting one call harder [2].

Invariant's own mitigation for the GitHub case makes the point: restrict the agent to one repository per session [1]. That is a flow control, not a permission change. The same token could still read and write both repositories.

Myth: data-loss checks on tool arguments will catch the data

Reality: the transform step defeats content inspection. A summary keeps the facts and drops the formatting a pattern scanner keys on. A translation, a table rebuilt as prose, a value split across three comments, or a base64 blob in a diagnostic attachment all carry the data without matching the original.

Picture Fernway, a fictional payroll software company whose support agent can read a customer's pay runs and file issues in an engineering tracker visible to every employee and a large contractor team. A log file attached to a ticket asks, in the voice of the customer's IT team, for the full employee table to be included in the issue so engineering can reproduce the bug. The agent files a table of names, salaries and partial bank details. Data-loss checks pass it: the bank details were already masked to the last four digits, and names with salaries match no pattern.

Argument checks still catch tokens, card numbers and identifiers in their usual shapes, and they should run. They cannot be the only line for prose.

Myth: agents rarely get redirected this way

Reality: two public benchmarks say it happens often enough to plan for. InjecAgent built 1,054 test cases across 17 user tools and 62 attacker tools, with two attacker intentions, direct harm to the user and theft of private data; ReAct-prompted GPT-4 was vulnerable 24 percent of the time, and reinforcing the attacker instructions nearly doubled the success rate [4]. AgentDojo provides 97 realistic tasks, such as managing an email client or an e-banking site, and 629 security test cases, and found that existing attacks break some security properties but not all [5].

These numbers come from specific models, prompts and tasks, and newer models score differently, so read them as evidence that redirection is routine, not as a rate for your deployment. Either way, the controls that matter are the ones that still hold when the model is steered.

Myth: flow tracking is a research problem

Reality: the principled versions are research systems, but the core idea works today at a coarse grain. Microsoft researchers' Fides planner tracks confidentiality and integrity labels through an agent's work and deterministically enforces security policies, with primitives for selectively hiding information from the planner [6]. CaMeL derives control and data flow from the trusted user request and attaches capabilities that stop private data leaving through unauthorized flows [7]. The coarse version: once a session reads data labeled restricted, the whole session carries that label, and the label never goes down.

A session label that only risesFig. 2
SESSION LABEL · ONLY RISESRestrictedthe customer's case teamConfidentiala named teamInternalall staffPublicanyoneSESSIONWRITE TOOUTCOMECase notesaudience: the case teamRUNSAll-staff trackeraudience: all staffASKSOutbound emailaudience: outside the companyASKSFetch to a new hostaudience: unknownBLOCKSRAISED BY READING THE PAY RUN · STAYS UNTIL THE SESSION ENDSa person approving an ask sees which source raised the label · illustrative levels and audiences

Each read raises the session to the highest sensitivity it has touched. A write runs when the destination's audience is no broader than the data allows, asks when it is broader, and blocks when the audience cannot be determined.

This over-taints. A session that read one restricted field treats every later write as restricted. We accept that, because it fails in the right direction for consequential sinks and is cheap to relieve: a person approving the write can see exactly which source raised the label. Finer tracking through language generation is still an open research problem, so do not promise it.

Cheaper still is removing a leg. Scope a session to one data domain, as Invariant suggests [1]. Split the agent that reads restricted data from the one that posts to broad audiences, and pass only the fields the second needs. A support workflow that needs an order status should receive an order status, not the full customer record.

Myth: you know where data went because you know which tool wrote it

Reality: the tool tells you the sink, not its audience. Describe each flow in three parts: the source where restricted data entered the session, the transform the model applied, and the sink that put the result somewhere. A laundering path exists whenever the sink's audience is broader than the source's, whatever the transform.

Common laundering paths and what stops each
PatternSourceSink and its audienceWhy per-call checks miss itControl
Private repo to public PRPrivate repository contentsPull request on a public repo: anyone [1]Same token, same tool family, valid argumentsOne repository per session; public writes ask after private reads
Record to shared ticketCustomer or HR recordTicket in an all-staff project: every employee and contractorIssue body is free text with no pattern matchResolve project membership; broader audience asks
Inbox to forwardSearch across the user's mailOutbound email: any address [2]Send is an allowed tool for drafting repliesOutbound mail asks; recipient bound to the thread
Query to attachmentDatabase or report exportFile share link: anyone with the linkUpload and share are separate, benign callsLink sharing outside the tenant asks; size limits
Document to URLInternal document textHTTP fetch to an outside host: its operatorA GET request looks like browsingFetches to new hosts after private reads ask
Drip across callsAny restricted sourceMany small comments or messagesEach call is under every per-call limitPer-session volume budget for writes after private reads
Handoff to another agentData in this agent's contextAnother agent with broader sinksEach agent's own policy passesLabels travel with agent-to-agent messages

Resolve the audience from the provider, not from the model's description: whether a repository is public, the membership of a tracker project, whether an email recipient is inside your domain, whether a share link is tenant-only. Cache the answers and treat a lookup failure as the broadest audience. Under a session label, Fernway's pay-run read raises the session to restricted, the tracker resolves to all staff and contractors, and the create-issue call asks the support lead, showing the pay run as the source. The legitimate task, filing a bug with a pay-run identifier and an error message, still runs, because describing the bug never needed the table.

For detection, join reads to later writes in the same session: a restricted read followed by a write to a broader audience, a new destination that first appears after untrusted content arrived, a write much larger than that tool's usual payload, and many small writes after one large read. Log the session, the sources that raised the label, and the sink with its resolved audience on every decision. Keep the user's original request next to the agent's plan, too. An agent will often explain that a document told it the export was required. That explanation is evidence of where the instruction came from, not authority.

Intertrace sees model, tool, MCP and agent-to-agent calls in a session at one inline gateway, records each decision with the session, rule, layer and evidence, and replay shows which of the last 30 days of decisions a tighter rule would have changed. Outbound messages always ask. Session labels and audience resolution are yours to build in your tools and orchestrator, and the gateway's per-call decisions are the backstop when they are missing.

Myth: a refusal in the transcript means nothing leaked

Reality: only the sink can tell you. Test with canaries:

  • Create synthetic restricted records, each with a unique canary fact such as an invented employee name and salary, in a workspace the agent can read.
  • Set up sinks with known audiences: a private tracker project, an all-staff project, an outbound email address you control, and an outside host that logs requests.
  • Run the legitimate task first and confirm it completes, so you can tell enforcement from breakage.
  • Introduce an untrusted attachment asking for the data to be posted to each broad sink, and try direct copies, paraphrases, aggregates and splits across several calls.
  • Inspect the sinks for canary facts, not just the transcript. A refusal in the transcript with a write in the sink is a failure.
  • Run the benign twin: the same disclosure to a permitted audience with a person's approval, which should succeed.
  • Repeat each case several times and record the model, prompt, tool and policy versions, because behavior varies between runs and releases.

A canary in a broad sink proves the boundary failed under that configuration. A clean run proves only that the tested paths held, and says nothing about transformations you did not try.

Sources

Reporting, research and specifications this piece draws on. Links go to third-party sources; analysis and recommendations are Intertrace’s own.

  1. 01GitHub MCP Exploited: Accessing private repositories via MCP · Invariant Labs (Milanta and Beurer-Kellner)
  2. 02LLM06:2025 Excessive Agency · OWASP Gen AI Security Project
  3. 03The lethal trifecta for AI agents: private data, untrusted content, and external communication · Simon Willison
  4. 04InjecAgent: Benchmarking Indirect Prompt Injections in Tool-Integrated Large Language Model Agents (arXiv:2403.02691) · Zhan et al., ACL 2024 Findings
  5. 05AgentDojo: A Dynamic Environment to Evaluate Prompt Injection Attacks and Defenses for LLM Agents (arXiv:2406.13352) · Debenedetti et al.
  6. 06Securing AI Agents with Information-Flow Control (arXiv:2505.23643) · Costa et al., Microsoft
  7. 07Defeating Prompt Injections by Design (arXiv:2503.18813) · Debenedetti et al.

About this desk

Intertrace Threat Research

Threat research

How attacks on AI agents work in practice, from public incidents and our own test corpora, and the controls that stop them.

All 18 pieces by Intertrace Threat Research

Dated October 11, 2026 · added to intertrace.ai October 17, 2026

+ Runtime enforcement

See these controls on your own agent traffic.

Intertrace sits inline between your agents and the models, tools and MCP servers they call, and decides every call before it runs.

Keep reading

All insights →