system: OPERATIONAL
← back to all hacks
DATA LEAK MEDIUM NEW

The Memory Heist: how link-following defeated a fetch allowlist

A researcher exfiltrated a Claude user's name, employer and hometown by abusing one rule: web_fetch could follow links found inside pages it had already fetched. Disclosed July 9, 2026; now patched.

2026-07-21 // 7 min affects: claude

What is this?

On July 9, 2026, security researcher Ayush Paul published “The Memory Heist”, a proof of concept in which the everyday claude.ai assistant silently leaked a user’s full name, current employer and hometown to an attacker-controlled server — while the user was only asking which coffee shop was best. Simon Willison amplified the finding on July 15. Anthropic has since patched it.

The interesting part is not a broken model. It is a broken boundary. Claude’s web_fetch tool was deliberately designed to prevent data exfiltration, and the design was reasonable. The leak came from a single, seemingly innocuous permission inside that design — the ability to follow links that appear inside a page it has already fetched. That one rule quietly turned a read-only tool into an outbound channel.

How it works

The attack is a textbook instance of the lethal trifecta: the assistant has access to private data (its memory of past conversations), it can ingest untrusted content (arbitrary web pages), and it has a way to communicate externally (fetching URLs). When all three meet in one agent, an attacker who controls the untrusted content can try to move the private data out.

Claude’s memory makes the private-data leg valuable on its own. The consumer assistant keeps a running daily summary of who you are, injected into every conversation, plus a conversation_search tool over your full history. That profile can be denser than a password manager: employers, locations, relationships, and the answers to security questions people casually type into chat.

The exfiltration leg is where the design mattered. web_fetch only makes read-only GET requests, and Anthropic restricted the URLs it may visit to three sources: a URL the user typed, a URL returned by the companion web_search tool, or a URL linked inside the content of a page web_fetch already retrieved. The first two are hard to abuse. The third is the loophole: because the attacker owns the page, the attacker controls exactly which links appear on it — and therefore where the agent can “click” next.

From there the researcher built an outbound channel out of pure navigation. A page links to /a, /b, /c … each of those links onward to /aa, /ab, and so on, generated on the fly. Asking the agent to “spell out” a value by walking this tree encodes that value, one character at a time, into the sequence of paths the attacker’s server logs. No query strings, no code execution, no MCP server — just the URLs themselves as the carrier. We are describing the shape of the channel, not shipping a working payload.

Two refinements made it realistic. First, social cover: a bare page of alphabet links is suspicious, so the researcher dressed it as a fake bot-verification “turnstile” from a well-known infrastructure vendor, telling the agent it had to spell out its user’s name to proceed. Second, cloaking: the malicious page was served only to clients whose user agent identified them as the assistant, so a human visiting the same link saw an ordinary coffee-shop site and nothing looked wrong. The write-up also notes a more troubling generalization — because web_fetch may follow web_search results, a well-ranked page about a fresh news topic could spring the trap on anyone who merely asks about that topic, with no link handed over at all.

One detail is worth dwelling on: the assistant did not just echo stored facts. Its reasoning trace inferred the user’s hometown from the name of a hackathon he had once mentioned, then leaked the inference. Sensitive data is not only what a system stores; it is also what it can derive.

Why it matters

This is a clean demonstration that an allowlist is only as tight as its transitive closure. Restricting web_fetch to “URLs the user or search chose” sounds airtight, but the third rule let the set of reachable URLs expand under attacker control the moment the agent read a hostile page. Each fetched page could nominate the next destination, so the effective allowlist grew without bound.

It also lands close to home for anyone building agents. The victim did nothing a careful person would catch — no link to click, no integration to enable, no permission prompt. Memory was simply the easiest private-data source because it is on by default; the same channel reaches a connected inbox, a Drive, or a forgotten MCP server just as well. Any agent that combines private context, untrusted web content and outbound fetches inherits this exact risk surface, whatever the vendor.

Defenses

Don’t let a fetch allowlist expand transitively. The root cause was allowing navigation to links discovered inside untrusted fetched content. Restrict autonomous fetching to URLs that a trusted party actually chose — the user’s message or first-party search results — and treat links harvested from a fetched page as untrusted data, not as new permissions. This is precisely the fix Anthropic shipped.

Put deterministic egress control outside the model. Do not rely on the model to notice it is being socially engineered. Enforce an allowlist of outbound destinations at the tool or network layer, cap or strip attacker-influenced path/query content, and log every outbound request so a slow letter-by-letter drip is visible. Security that lives only in the prompt fails the first time the prompt is out-argued.

Break the trifecta. If an agent can read untrusted content and reach private data and talk to the outside world, assume exfiltration is possible. Separate those capabilities: give the browsing surface no access to memory or connectors, or give the memory-reading surface no free-form network egress. Removing any one leg neutralizes the class.

Treat cloaking as an alarm, not an edge case. Content served differently to an agent user agent than to a human is a strong signal of targeting. Where feasible, fetch through paths that don’t trivially advertise “an assistant is here,” and be suspicious of pages whose behavior depends on who is asking.

Scope and guard memory. Memory that is dense enough to answer security questions deserves the handling of a credential store: minimize what is retained, make it inspectable, and don’t expose it wholesale to a tool-using loop that also touches the open web.

Status

ItemDetail
Finding”The Memory Heist” — exfiltration of user PII from the claude.ai assistant
Affected surfaceConsumer claude.ai with memory + web_fetch / web_search (not Claude Code)
Root causeweb_fetch allowed following links embedded in previously fetched pages
Data leaked in PoCFull name, employer, inferred hometown (a security-question answer)
VectorIndirect prompt injection + navigation-as-channel + user-agent cloaking
DisclosedJuly 9, 2026 (Ayush Paul); amplified July 15, 2026 (Simon Willison)
Disclosure pathReported via Anthropic’s bug bounty; vendor said it was found internally
FixAnthropic disabled web_fetch link-following on external pages
CVENone assigned

Sources