Your agents write the titles your trackers read.
An IMDEA audit of 9 AI chat services found trackers receiving titles, permalinks and screenshots, not just prompts. Agent swarms multiply those artifacts.

The riskiest sentence in an AI product is often not the one the user typed. It is the one the model wrote about what the user typed.
Researchers at IMDEA Networks analyzed the web and mobile clients of nine conversational AI services in “Prompt like a Butterfly, Sting like a Tracker”. Prompts did leak. So did a quieter class of data: the titles, permalinks and screenshots the services generate around a conversation, often sent to third-party trackers together with a persistent user identifier. A team that only guards the prompt is guarding one copy out of several.
That finding gets worse when you move from a chat UI to an agent platform. The mapping is not one-to-one. It is one-to-many. Below we map the paper's artifact taxonomy onto agent platforms, show the defaults agent-swarm ships today, and argue for one rule: anything a model writes after reading a prompt is prompt-grade data until proven otherwise.
What did the IMDEA audit find?
The paper's abstract says multiple providers disclose “conversation-derived artifacts—including titles, prompts, and screenshots” to third parties, “often alongside persistent user identifiers that enable user attribution.” It also finds that some providers expose conversation permalinks without access controls, “allowing trackers to read the entire conversation.” The press release names Meta and Google among the trackers receiving chat titles and permalinks. The project site lists one web client sending conversation URLs to Datadog with the user's raw email address, where the URL encodes the text of the chat's first query.
The taxonomy matters for what comes next. The paper points at data that sits next to the conversation rather than inside it:
- Auto-titles. The model reads the conversation and writes a short label for the sidebar, such as “Symptoms after starting new medication.” The title is a compression of the prompt, including whatever the user did not think to redact.
- Permalinks. Shareable URLs that resolve to conversation content. When they flow into observability tools as page views or error context, they travel with a persistent user ID. If they need no login, anyone holding the link can read the conversation.
- Telemetry context. The URL, the title and the user ID bundled into an analytics event or an error breadcrumb, then shipped to monitoring vendors that were never meant to store conversation content.
- Screenshots and previews. Rendered images and link-preview metadata of a conversation. The project site describes shared conversations whose preview metadata carried verbatim message text to a third-party tracker.
The pattern is not malice. It is a category error. Engineers treat a title as metadata, like a filename, and metadata gets logged everywhere. A model-written title is not metadata. It is a summary, and a summary of a sensitive thing is a sensitive thing.
The swarm multiplier
A chat app writes one auto-title per conversation, and a person usually glances at it. An agent platform writes model-generated artifacts on every run, and nobody looks at them.
Count the artifacts: task title, run URL, PR title, Slack unfurl, share link, screenshot. That is six model-written or model-adjacent strings, all derived from a prompt that names a vendor and implies the legal team made a mistake. A chat app would have produced one risky title. The swarm produced six, and each can reach your observability stack, your error tracker, your analytics, your Slack search index and your link-preview cache.
The multiplier is per run, per agent and per retry, not just per task. A swarm doing real work emits these artifacts at machine cadence, and no person chooses the wording. That is the point of a swarm. It is also why the IMDEA finding scales so badly.
Mapping the taxonomy onto agent platforms
This is the mapping we use when we audit an agent system. Each row is a place where a model-written string can cross a trust boundary you thought you had.
| Chat artifact | Agent platform equivalent | Where it leaks |
|---|---|---|
| Auto-title | Task title, run name, PR title, commit message | Analytics events, error breadcrumbs, Slack unfurls, GitHub notifications |
| Permalink | Run URL, share link, trace URL | RUM and error-tracking context, link-preview caches, referrer headers |
| Persistent user ID | User or org ID on every span and event | Joins artifact content to identity across third-party systems |
| Page content | Screenshots, session replay, DOM snapshots | Full prompt and output captured as “UI state” |
People forget the last row. Session replay and screenshot tools capture the rendered page, and in an agent UI that page holds the prompt and the model's output verbatim. If the replay tool is a third party, you have shipped the conversation itself, not an artifact of it. Replay is genuinely useful for debugging agent misbehavior, which is exactly why it tends to get switched on and left on.
What agent-swarm defaults to
We did not write these defaults with this paper in mind. They come from one rule: every model-generated label is prompt-grade data. It gets the same handling as the prompt. There is no exception for “it's just a title.” Four defaults in the open-source codebase follow from it.
1. The harness does not log prompts or tool content unless you ask
When harness telemetry is on, the Claude adapter hands the Claude Code process four privacy defaults. Each applies only if the operator has not set that variable, so turning content on is an explicit choice:
// src/providers/claude-adapter.ts
const privacyDefaults: Record<string, string> = {
OTEL_LOG_USER_PROMPTS: "0",
OTEL_LOG_TOOL_DETAILS: "0",
OTEL_LOG_TOOL_CONTENT: "0",
OTEL_METRICS_INCLUDE_ACCOUNT_UUID: "false",
};
for (const [key, value] of Object.entries(privacyDefaults)) {
if (sourceEnv[key] === undefined) {
otelEnv[key] = value;
}
}The gate sits where telemetry is produced, not in application code. Application developers will always find a reason to log “just this one field.” A default at the exporter boundary does not care about their reasons. The observability guide covers how to enable telemetry and override these flags.
2. Background events carry enums and a domain, never free text
The dashboard's notification events go to our own feedback endpoint. The content of each event is a fixed key and an action. When a user submits an email, the event records only its domain, never the address:
message: `[notification_event] key=${notificationKey} action=${action}${
emailDomain ? ` domain=${emailDomain}` : ""
}`,These events are not anonymous: they carry a user ID and an install ID so we can count distinct installs. What they cannot carry is a model-written string. There is no field a task title could slip into. They also honour the operator's ANONYMIZED_TELEMETRY opt-out and send nothing until the dashboard knows that setting.
The pull to add a task_title field is real, because it makes dashboards readable. We resist it. A dashboard your team can read is also readable by whoever processes the event, and the IMDEA findings are what that trade looks like when it is made by default.
3. Share links expire within an hour
The permalink finding maps most directly onto agent platforms, because “send this result to a teammate” is a core workflow. In agent-swarm, file links are signed URLs, and the request schema caps their lifetime at 3,600 seconds. A link that leaks into a log or a Slack channel grants at most an hour of read access to one file, then nothing. That changes the blast radius from permanent to time-boxed.
4. Analytics is a build flag, and self-hosted builds ship none
The dashboard injects Plausible, a cookieless analytics tool, only when VITE_PLAUSIBLE_ANALYTICS is set at build time. Our hosted production build sets it. Self-hosted and local builds ship with no analytics script at all. It is the boring choice, and the only one that is structurally safe: you cannot leak to a vendor you never load.
Why are swarms worse than chat apps for this leak?
Volume is half of it. The other half is where the model sits. In a chat app, the model writes a title for a conversation a person is reading. That person is a plausibility check: if the title is wrong or embarrassingly specific, someone notices.
In a swarm, the model writes artifacts for other machines. The scheduler consumes the task title. GitHub's API consumes the PR title. A webhook consumes the Slack message. No plausibility check exists anywhere in that loop. The artifact pipeline is automated end to end, so a leak in it is automated end to end too.
What does not work
- Regex redaction. Scrubbing titles for emails, phone numbers and API keys catches what looks like a secret and misses what is one. “Review Acme contract indemnification clause” matches no PII pattern, and you still do not want it in a vendor's logs. Sensitivity is semantic, not syntactic.
- A second model that sanitizes titles. You send the sensitive title to another model, which is another artifact pipeline with the same problem, plus latency, cost and a new failure mode where a bad paraphrase gets logged. You add a second leak to fix the first.
- Trusting the vendor's data-processing agreement. A DPA is a legal instrument, not a technical control. A permalink ends up in an error tracker because someone added
window.location.hrefto the error context, a reasonable move under the wrong mental model of what a URL can contain. Contracts do not refactor code. - Client-side gating. If the decision to send a title to analytics lives in the frontend, QA can disable it by accident and a growth experiment can route around it. The gate belongs where data leaves your infrastructure: the exporter, the proxy, the instrumentation layer.
The audit checklist
Run this on any agent platform, ours included, every quarter. Each item is a place where a model-written string can cross a trust boundary.
- List every model-generated string. Task titles, run names, PR titles, commit messages, Slack messages, email subjects, summaries and error messages the model rewrote. If a model wrote it after reading user input, it goes on the list.
- Trace each string to every sink. Logs, spans, analytics events, error reports, third-party APIs, link unfurls, caches, screenshots, session replay. The sink list is always longer than you think.
- Check every URL for content. Do run URLs, share links or trace URLs embed titles in slugs or query parameters? Do they grant access without auth? Do they expire? A URL is a string, and strings get logged.
- Confirm the gate is at the boundary. Is content filtering enforced in the telemetry exporter or in application code? Application-level gates erode. Boundary-level gates hold.
- Drop persistent IDs from third-party payloads. If a monitoring vendor can join an artifact to a stable user ID, you have built a cross-system profile of what your users ask your agents. Hash, rotate or drop.
- Audit screenshots and replay separately. They capture prompts and outputs verbatim. They are not artifacts of the conversation. They are the conversation.
- Test the defaults, not the configuration. A fresh deploy with no config should be the safest deploy. If safety depends on remembering a flag, someone will forget the flag.
The stance
Not everyone will agree with this: if your agent platform's default telemetry includes any model-generated string, it is not production-ready, however good the agents are. The industry has spent years hardening the prompt path with system-prompt isolation, injection defenses and output filtering, while the artifact path stayed open. The IMDEA paper audits chat apps. Nobody has published the equivalent audit of agent platforms yet. When someone does, expect the same shape with a larger blast radius, because we automated the artifact pipeline and removed the person who used to glance at the title.
The fix is not complicated, just unfashionable: default to silence. Log identifiers and counts. Keep content behind flags that are off. Make share links expire. Load no third party you do not need. Treat every label a model writes as if it were the prompt, because to anyone reading your trackers, it is.
For the rest of our security model, see how the OWASP agentic top 10 played out in our swarm and why credentials never enter agent context.
/ references
Sources and further reading
FAQ
What did the IMDEA privacy audit find?
IMDEA Networks analyzed the web and mobile clients of nine conversational AI services. Several providers sent conversation-derived artifacts, including titles, prompts and screenshots, to third parties, often alongside persistent user identifiers. Some exposed conversation permalinks without access control, so a tracker holding the link could read the whole conversation.
Why are agent swarms worse than chat apps for this leak class?
A chat app writes one title per conversation, and a person usually sees it. A swarm writes task titles, run names, PR titles, Slack messages and share links on every run. Machines consume them, nobody reviews them, and each one can carry prompt-grade data into telemetry.
What is prompt-grade data?
Prompt-grade data is any string that can hold the same sensitive content as a user prompt. If a model wrote it after reading the prompt, it can leak the prompt. Auto-titles, summaries and PR descriptions all qualify, so they need the same handling as the prompt.
How does agent-swarm handle this by default?
The harness sets OTEL_LOG_USER_PROMPTS, OTEL_LOG_TOOL_DETAILS and OTEL_LOG_TOOL_CONTENT to 0 unless the operator overrides them. Dashboard background events carry enums and an email domain, never free text. File links are signed URLs that expire within an hour. The dashboard loads Plausible only when a build flag is set, so self-hosted builds ship no analytics script.
What should I audit first on an existing agent platform?
Grep your telemetry exporter for every field a model touched. Task names, span attributes, error messages and share URLs are the usual suspects. If any of them is a model-written string, treat it as prompt-grade and send it down the same redaction path as the prompt.
Related field notes
The Write-Only Radar: Our Curation Agent Proposed the Same Story for 21 Days
When every node stays green while producing duplicate work, your data model is lying to you.
25 FOSS repos agent-swarm stargazers love, and will become key for your agentic infra.
We looked into 528,916 star edges, 228,177 distinct repositories, from 655 agent-swarm GitHub stargazers.
Orchestrator Loops Are a Trap: Why Process-Level Orchestration Wins
Why recursive Agent/Task tool calls collapse in production and how Agent Swarm uses independent Claude Code processes with external runners instead.