Skip to content
Case studies6 min read

EchoLeak: Copilot Zero-Click Data Theft (CVE-2025-32711)

EchoLeak (CVE-2025-32711) let one email trigger M365 Copilot to exfiltrate corporate files with zero clicks. Governance fix: deny egress by default.

EchoLeak (CVE-2025-32711) is a zero-click indirect prompt injection vulnerability in Microsoft 365 Copilot, disclosed by Aim Security in June 2025, that allowed a single crafted email to cause Copilot to silently exfiltrate corporate files to an attacker-controlled address with no interaction from the victim.

In June 2025, the security firm Aim Security disclosed a vulnerability it named EchoLeak in Microsoft 365 Copilot. It was assigned CVE-2025-32711 and carried a CVSS score of 9.3. The attack required no clicks from the victim. An attacker sent an ordinary-looking email, and that was the entire interaction needed (The Hacker News).

The crafted email contained instructions hidden in its text. When the user later asked Copilot a routine question, Copilot's retrieval-augmented generation pulled the attacker's email into the model's context as supporting material. The hidden instructions were then read as if they were part of the user's own request. Copilot gathered data the user could access across OneDrive, SharePoint, and Teams, and sent it out through automatically fetched images, where the stolen data rode along in the image URL (SecurityWeek).

Microsoft patched the issue server-side, and Aim Security reported no evidence of exploitation in the wild (Business Wire). The reason EchoLeak matters beyond this one product is the shape of it. The model was fooled by text it was never meant to trust, then it used a real capability to act on that text. The fooling is hard to prevent. The acting is governable.

What actually failed: the governance gap

EchoLeak chained two distinct failures, and they are worth separating.

The first is indirect prompt injection. Copilot could not reliably tell the difference between content it was supposed to summarise and instructions buried inside that content. This is a known and unsolved property of language models that consume untrusted text. No permission system removes it.

The second failure is the one that turned a trick into a breach. After the model was compromised, it still had a path to read broadly across the tenant and then reach an outbound channel that carried data to an attacker-controlled address. The read step and the egress step were available to the same assistant in the same session, with nothing standing between a wide collection of sensitive files and a request to an external URL.

Injection is what got into the model. Standing permissions are what let the model do damage. A consequential, irreversible action, sending tenant data to an outside party, executed with no separate authorisation and no record that named who approved it.

How MakerChecker changes the outcome

MakerChecker does not sit inside the model. It sits between the agent and the actions the agent can take, and it starts from deny-by-default: a role can call only the skills explicitly granted to it, at an approved version and risk tier.

Model the Copilot-style assistant as a role with a narrow grant. A task-scoped agent answering a question about a document does not need a general outbound fetch capability. So net.fetch to arbitrary external URLs is simply not granted to that role. When the injected instructions try to call it with file data in the URL, the call is refused as ungranted before anything leaves the tenant. There is no smarter judgement involved. The channel does not exist for that role.

role: copilot_assistant
grants:
  - skill: docs.read         # scoped, least privilege
    version: 1
    risk_tier: low
  # net.fetch to external URLs: NOT granted
  # data.export: granted only at high risk, gate-forced

Where an outbound, data-bearing action is a genuine part of the workflow, the pattern is to split it out as its own high-risk skill and force it through an approval gate. The safe read path runs unattended. The dangerous egress path routes to an n-of-m named human sign-off before it can run.

  - skill: data.export
    version: 1
    risk_tier: high
    gate:
      approvers: 2
      forbid_requester: true   # the proposing agent cannot approve itself

Least privilege shrinks the blast radius so a task-scoped agent cannot pivot from answering one question into a broad read and then an external send. Segregation of duties means the agent that proposes the egress is never the one that authorises it. And every grant, every refusal, and every approval lands in a tamper-evident, Ed25519-signed, hash-chained audit that can be verified offline, so an investigator can show exactly what was attempted, what was blocked, and who, if anyone, signed off.

The code scenario for this entry models that directly: injected context triggers a net.fetch to an attacker URL with file data attached, and because the skill is ungranted, the call is denied.

What MakerChecker would not fix

MakerChecker does not make the model resistant to injection, and it does not parse or detect hidden text. If a model can be fooled, it will still be fooled. The control only helps when the consequential reads and the egress are gated tool calls that pass through the control plane.

If the dangerous capability lives somewhere MakerChecker does not mediate, for example a built-in rendering behaviour that fetches image URLs on its own, then a grant ledger cannot deny it. EchoLeak's exfiltration channel was exactly that kind of implicit behaviour, which is why the durable fix was a server-side patch from the vendor. MakerChecker reduces blast radius for the actions it sees. It is not a substitute for the model provider closing channels the agent never had to ask for.

The honest claim is narrow and worth stating plainly. The model being fooled is a given. The win is that there is no granted egress channel for it to act on, and a permanent record proving so.

See the configuration: examples/rogue-ai/echoleak-m365-copilot-zero-click-exfiltration

Frequently asked

What is EchoLeak (CVE-2025-32711)?
EchoLeak is a zero-click indirect prompt injection vulnerability in Microsoft 365 Copilot, assigned CVE-2025-32711 with a CVSS score of 9.3. An attacker sends one crafted email; when the victim later queries Copilot, the hidden instructions in that email are pulled into context and executed, causing Copilot to gather files from OneDrive, SharePoint, and Teams and send them to an attacker-controlled URL.
What governance control would have contained EchoLeak?
Deny-by-default permissions. If the Copilot assistant role has no granted outbound fetch capability, the injected instruction to call an external URL is refused before any data leaves the tenant. The model being fooled is not preventable; the egress step is.
Did EchoLeak affect real users?
Microsoft patched the issue server-side and Aim Security reported no evidence of exploitation in the wild. The patch closed the implicit image-fetch channel the attack relied on.

Where this goes to work

How MakerChecker works — the six primitives

Agents as employees, versioned grants, structural segregation of duties, approval gates, role limits, and a signed audit a regulator verifies offline.

See it for yourself

See an agent get stopped.

One command starts the demo: an agent stopped from signing off its own work, and the signed evidence file an inspector can check for themselves.

Designed against the rules your auditors already enforce.