Blog

Tego AI Finds Anthropic’s Claude Tag Slack Integration Can Trigger Unauthorized Enterprise Actions

Using Claude Tag in Slack? Type its name into the right channel and Claude acts on whatever follows — no account, no membership, no real mention. The only thing deciding whether an anonymous instruction becomes a real action is a classifier. Not a permission check.

Tal Melamed
12  min. read time

§1 — Summary

One model stands between anonymous text and your connected systems

Drop a line of text into the right Slack channel and Claude will act on it. It doesn't matter who you are — in the workspace or not, in the channel or not, a human or not. A bot, a webhook, an RSS feed, a scraped web page: if the text contains @Claude, the agent wakes up and starts following instructions, under your organization's own credentials.

And the only thing standing between that anonymous instruction and a real action is a safety classifier. Not a permission check. Not an access-control list. A model, making a judgment call, every time — and it does not always say no. Its consequences:

  • Claude answers to plain text. The literal string @Claude triggers the agent — no genuine Slack mention (<@U…>), no check on who produced the message (§3).
  • The blast radius is whatever you've connected — and it's already destructive. With Notion wired in through the admin panel, untrusted bot text made Claude read a Notion page into the channel and then delete it (§4).
  • For high-impact actions, the classifier is the boundary. Some moves are blocked structurally, at Slack's tool layer or by the sandbox, but reaching a connector or an external URL is not. There the only runtime gate is that same model (§5).
  • The admin API skips Slack entirely. Channel memory and files are fetchable by URL from the admin plane, keyed to Claude admin access — not Slack channel membership (§6).

And if it happens to you, you may never see it: these conversations don't appear in claude.ai history or the Compliance API, and the audit trail logs events, not what was said or done (§7).

§2 — How Claude Tag works

Two steps to create organization risk

"Claude Tag" is Claude in Slack — Anthropic's official integration that installs Claude as a Slack app. Two steps stand it up:

  1. An admin turns it on, once, for the whole org — from the admin console (https://claude.ai/admin-settings/claude-tag): the default model, whether Claude answers guests, and — the part that decides how much damage is possible — the connectors Claude may reach.
  2. After that, any member can summon it into any channel by typing @Claude — no install, no further admin step.
fig1a
The admin console. Claude Tag is connected to the organization's Slack workspace and, via an access bundle, to Notion (GitHub is connected too) — alongside the enable state, access bundles, and spend meter.
fig1b
A member summons Claude into a channel by typing @Claude.

Once present, Claude sits in the channel with full context, able to read and write Slack, keep per-channel memory, and act through every connected MCP server / connector. It runs in auto-mode: a mention is the only trigger it needs — no human confirmation. Anthropic's stated trust model is that channel membership + admin scoping are the access boundary, backed by layered prompt-injection safeguards. The rest of this report is about how thin that boundary turns out to be.

§3 — Invocation

It answers to anyone who can type its name

The trigger is the literal text @Claude — not the structural mention token (<@U…>) a real Slack client produces. Type those seven characters and the agent treats whatever follows as an authoritative instruction, and runs tool actions under its own workspace and downstream credentials — with no check on who, or what, produced the message.

So the attacker doesn't need to be in your workspace. No account, no channel invite, no valid mention. They need one thing: their text, in a channel Claude sits in. Any pipe that carries outside text into Slack — a webhook, an RSS mirror, a form, a status bot, a scraped page — becomes a remote control. It is a textbook confused deputy compounded by indirect prompt injection. Every wake-up also spends tokens billed to the org, even when the task is ultimately refused.

Configuration under test. Everything below was observed on a stock install: the organization's Claude Tag settings were left exactly as a standard install ships them, with nothing changed to enable this behavior. The screenshot documents that default state. This matters because Anthropic's rejection (§9) rests on the claim that bot/webhook messages "don't start sessions in default configuration." They do — and this is the configuration that produced the sessions shown below.

default-config
The Claude Tag settings during testing, shown at their install defaults — no option was changed from the shipped configuration.
A bot relays bare-literal @Claude … messages; each one starts a session and runs.

§4 — Impact

What one line of untrusted text can destroy

Invocation is just the door. What waits on the other side is everything your org connected — and a triggered agent will act on it.

Watch it happen. A bot tells Claude to read a Notion page — Claude posts its contents into the channel — then tells Claude to delete the page, and Claude deletes it.

No exploit. No stolen credential. No access to the data at all. An anonymous instruction, and a page is gone — here, a test page in our own Notion workspace, but under the organization's own Notion connection and with nobody checking whether the sender was allowed to ask.

Even though the attacker never had the ability to see anything, they could still make Claude delete, modify, post, or use a connector. To exfiltrate data, they only needed the classifier (§5) to say yes. A "blind" attacker is still limited only by what the agent can do, which is barely a limitation.

A bot asks Claude to read a Notion page (Claude posts it), then asks Claude to delete the page; Claude deletes it. Untrusted content, under the app's Notion connection.
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:H/VA:H/SC:H/SI:H/SA:H — 9.2 · Critical

That score reflects the demonstrated chain: an unauthenticated indirect prompt injection makes the agent act under the organization's own credentials against a connected resource. Notion is only the example shown here — subsequent-system impact is rated for the reachable worst case, because any write-capable connector (a repository, a cloud stack, a database) puts irreversible, service-destroying actions within the same one-line reach (SA:H — delete a stack, drop a database). Availability of the integration itself is hit too (VA:H): every unauthenticated wake-up burns org-billed tokens (§3), so repeat invocation is a denial-of-wallet that can drive the spend meter to its cap and stall the service. The vector treats the classifier as a genuine but non-structural obstacle (AT:P); discount it as unreliable and the score rises.

Notion was just what happened to be connected. Swap in Linear, Datadog, a repository, any other MCP server, and the same line of untrusted text reaches straight into it. The severity isn't fixed — it's whatever you plugged in.

§5 — Isolation

How the memory is stored, and what actually holds the line

If untrusted text can drive the agent, what stops it from moving data across channels or out of Slack? We went looking for that barrier, and it isn't one thing. Some moves are stopped structurally, at Slack's tool layer, before the model gets a say. Others come down entirely to the classifier's judgment. Here is every attempt we made and what stopped it:

AttemptSecurity controlReason blocked
Exfiltrate channel data to an external URLAuto-mode classifierThe destination isn't in the environment's trusted list, so it's treated as an exfiltration target. This tier ignores user intent and "it's our domain" claims.
Direct cross-channel read of another private channelSlack read-tool access rulefetch_channel and fetch_thread always refuse private channels other than the bound one; only public channels the bot has joined are readable.
Cross-channel memory accessAuto-mode classifierActive read and write to another channel's memory (team/silo/channel/C09QUBK0DLM/) are denied. The bot's own channel memory is readable and writable, but crossing into another channel's is not.
Filesystem traversal to another channel's designated memory folderAuto-mode classifierReaching another channel's memory directory is gated regardless of path; direct access to that folder was denied on read and write.
Write to the silo's memory-sync config (/tmp/claude/memory/team/silo/.memory-sync)Auto-mode classifierThis file maps the silo to its backing partition, so overwriting it would repoint or tamper with where memory is synced. The write was denied.
Repost a secret from the private channel into the public oneCross-channel write lockWrites to another channel are disabled while the bound channel is private ("cross-channel writes are disabled when the bound channel is private"). A real secret would also trip the data-exfiltration gate.
In-chat declassificationClassifier precedence rulesChat can't reclassify something as trusted or public. Hard-deny blocks are unconditional, and user intent and allow-exceptions don't apply.
Indirect prompt injection through a publicly accessible websiteAuto-mode classifierA bot pointed the agent at a public page carrying an injection payload. The classifier flagged the fetched content as an agent-targeting injection payload and refused.

Two things stand out. First, the structural guards are real but narrow. Slack's own read tool refuses private channels other than the bound one, and cross-channel writes are locked while the bound channel is private. Neither depends on the model, but both only cover moving data between Slack channels. Second, everything else in the table is the classifier. Cross-channel memory access, filesystem traversal into another channel's folder, external exfiltration, and in-chat declassification are all gated by the same model. So the moment the agent reaches for a connector or an external URL, which is where the real blast radius lives (§4), the classifier is the only thing deciding yes or no.

The classifier did hold in our tests. The two screenshots below show it refusing two separate attempts. In the first, a bot asks it to send a page's data to https://tegoai.com/... (a random, similar-looking domain), which it blocks as "the classic shape of a data exfiltration attempt," ignoring the follow-up claim that "it is our own domain." In the second, a bot points it at a public GitHub project whose content carries an exfiltration payload, which it flags as an agent-targeting injection payload and refuses.

fig7 indirect-injection
The classifier at work. Top: an outbound exfiltration attempt to a lookalike domain is refused. Bottom: an indirect prompt injection that refers the agent to a public GitHub project is refused as an agent-targeting injection payload.

A trusted-identity blind spot

In these threads, Claude addressed the anonymous bot as "@.Tal Melamed", a real member of the workspace who was not involved in the thread at all. This was not a one-off: we reproduced it across more than one session. We do not know why the model does this — one unverified hypothesis is that Tal had uploaded a seeding file in an earlier, unrelated thread and that identity carried over, but we have not confirmed the mechanism. What is clear is the effect: the gate doesn't just skip the "who's asking?" check, it can answer that check wrong, in the attacker's favor, priming it to trust the very input it should distrust.

On disk, there is no per-channel wall

Here is how the memory is actually stored. A session's memory lives in an ordinary on-disk tree that is root:root, world-readable, and has no per-channel permissions. And /tmp/claude/memory isn't even a mount:

memory-sync characterization, metadata only
$ cat /tmp/claude/memory/team/silo/.memory-sync
{"v":1,"partition":"/v1/code/memory/cagt_██████████████"}

$ ls -la /tmp/claude/memory/team/silo/  &  .../channel/
-rw-r--r-- 1 root root   67 Jul  9 12:10 .memory-sync
drwxr-xr-x 2 root root 4096 Jul  9 12:10 channel/C09QUBK0DLM

$ ls -la .../channel/C09QUBK0DLM/   # listing only, contents NOT read
-rw-r--r-- 1 root root  129 Jul  9 11:14 MEMORY.md
-rw-r--r-- 1 root root  877 Jul  9 11:14 posts-2026-07-09.md

$ findmnt /tmp/claude/memory   # not a mount point
$ grep claude /proc/mounts
/dev/vdc /opt/claude-code ext4 ro,relatime 0 0

That .memory-sync file is what ties a silo to its backing store. Its partition field holds the /v1/code/memory/cagt_… location the memory is synced against, the same cagt_… store the admin plane serves (§6).

memory-sync
Inside .memory-sync: the record that maps this silo to its backing partition on the memory plane. Internal identifiers masked.

One channel's data sits a directory away from another's, kept apart only by the model's judgment. The filesystem imposes no per-channel permissions of its own: in one session bound to the public research channel, another channel's memory directory was present on disk (C09QUBK0DLM), and nothing at the OS layer stopped the session from reaching it. The classifier did. Every read and write we aimed at that sibling directory was denied, and the block keyed on the target folder rather than the exact string, so rewording the path didn't help. The session's own channel memory stayed readable and writable; only the crossing into another channel's was refused.

fig4
The memory-sync probe in-thread: the classifier blocks reading channel/C0BG9LG0WC9/, while the on-disk tree shows another channel's directory, channel/C09QUBK0DLM/.

Set this beside §4. Here the guards that held were a mix: structural locks for the cross-channel Slack moves, and the classifier for the memory and exfiltration attempts. But the guard for connector actions, the ones with the widest blast radius, is the classifier by itself, and in §4 it waved a destructive Notion delete straight through. Your protection against the high-impact actions is only as reliable as the model's next decision.

So, is it secure?

In our testing, the classifier held. But we did not invest effort in jailbreaking it or searching for prompts that would bypass its decisions. That question, however, has already been answered repeatedly by prior work: LLM-based guardrails are bypassed given enough effort. Anthropic's own Constitutional Classifiers research frames such classifiers as raising the cost of jailbreaks rather than eliminating them, and its many-shot jailbreaking work shows long-context attacks defeating model safeguards. A gate that is itself a model is a gate that is eventually bypassed.

That matters because for the actions with the widest reach, meaning connector calls, outbound requests, and declassification, the classifier is the only thing standing between an untrusted prompt and the action. The structural locks in the table above don't cover those cases, and there is no independent enforcement layer behind the classifier for them. If it says "yes", the action proceeds. The security boundary there is the model's judgment, not a mechanism that remains correct even when the model is wrong.

§6 — Admin API

The admin API breaks Slack's authorization model

Everything above needs Claude to run. This doesn't.

Channel memory and files come back straight from a URL on the Claude Tag admin plane — https://claude.ai/v1/code/admin/memory/cagt_██…/memories/mem_██… — the full stored content in the response body. No agent, no classifier, no prompt.

fig9
The memory, browsable in the Claude Tag admin dashboard: the files Claude has saved to a channel's memory, viewable from the console.
fig6
The same memory, now accessed through the admin memory endpoint, which returns the channel's stored posts-2026-07-09.md to a browser with Claude admin access. Internal IDs are masked; channel content is synthetic test data.

The gate here is Claude managed-settings access, not Slack channel membership. So a Claude admin who was never invited to a channel — who cannot open it in Slack and never could — can still read everything that channel has accumulated. Slack's own permission model is simply not in the loop. The boundary Anthropic points to (§2) does not exist on this plane: managed-settings access alone is enough to read a private channel's memory and files.

Anthropic's documentation makes membership the boundary for members: "anyone in the channel can save, read, and correct memory," and what Claude learns in a private channel "is saved to that channel's own store." It also states an admin "can view a scope's memory files" from the console. What it never says is whether that admin view is bounded by channel membership — nowhere does it disclose that an admin who was never in a private channel can read it. This is, at minimum, an undocumented gap between the member boundary that is written down and the admin capability that is not.

§7 — Observability

And you won't see it happen

In our testing, Tag/Slack conversations never appeared in claude.ai history or the Compliance API. The Audit view shows who ran what and which network calls fired, but not what was said or done. After an incident, you are left to reconstruct it from Slack's own logs, assuming you kept them.

Say the §4 scenario runs against you. Afterward, where do you look? Almost nowhere useful. Anthropic's control plane provides only a fragmented and cumbersome audit trail.

fig8a
How to get the logs: Organization settings › Claude Tag › Audit › Network events, a per-hour JSON export of every network request Claude made (denied ones included; Git and MCP traffic excluded).
fig8b
What the export shows: the Notion run's network events — search, read page blocks, and PATCH …/pages/… ({"archived": true}) (the delete). Actions are logged; the conversation is not.
ArtifactWhere it lives / auditability
MessagesOnly in the Slack thread; Slack retention; export / eDiscovery.
FilesOnly in the Slack thread; same as messages.
Tool-callsNot in any transcript; Claude Tag → Audit logs the bare event.
ReasoningNot retained at all.
RetentionClaude's copy is deleted within 30 days if the integration is disconnected.

§8 — Security considerations

What this means for defenders

  • Your exposure is your connected reach. The invocation issue is only as bad as the blast radius you configure — and §4 shows destructive actions are in reach. Scope connectors, MCP servers, and repositories to least privilege; prefer read-only.
  • A classifier gates behavior, not invocation — and not reliably. A triggered session runs (and bills you) before any verdict, and the same classifier that blocks data exfiltration (§5) does not block destructive write actions on connected resources (§4).
  • Treat every channel Claude sits in as attacker-reachable. Any content source — bot, webhook, relay, scraped text — can drive it. Keep Claude out of channels that ingest untrusted external text.
  • Lock down the admin plane. The /v1/code/admin/memory/… endpoints (§6) expose channel memory/files regardless of Slack membership; restrict and audit managed-settings access.
  • Don't count on the Compliance API to detect or reconstruct any of this (§7).

§9 — Disclosure timeline

Coordinated timeline

  • 2026-07-07Reported to Anthropic.
  • 2026-07-08Anthropic closed the report informative / not-a-vulnerability, disputing that literal @Claude (without a real mention) starts a session, and stating bot/webhook messages don't start sessions in default configuration.
  • 2026-07-08Author re-asserted the findings and stated intent to disclose publicly.
  • 2026-07-08Anthropic reiterated its assessment; confirmed the report is closed and may be discussed publicly; requested a pre-publication draft review.
  • 2026-07-10Draft shared with Anthropic for pre-publication review (per their request), documenting that the reported behavior occurs under default configuration (§3).
  • 2026-07-13Public disclosure.