Preventing a Slack MCP Agent from Reading Private Channels and DMs It Was Never Granted
Constrain the agent at three layers. First, give it a dedicated Slack identity with the narrowest scopes and channel membership. Second, expose only the MCP tools the task needs, with parameters restricted to granted conversations. Third, enforce policy on every tool call and on returned content in the execution path, because static Slack permissions do not control which conversations the agent requests at runtime. Retain evidence of the grant, each decision and each result.
Evidence to retain for an auditor
- The grant: app identity, token type, scopes, channel membership and the tool allowlist in force for each agent instance.
- The policy: the version of the rules applied, including the list of granted conversation IDs.
- Each tool call: tool name, parameters and timestamp, including blocked and rate-limited attempts.
- Each decision: allow, redact, block or escalate, with the rule that produced it.
- The originating input that led to the call, so injected or unexpected requests can be traced.
- Approvals: who approved, what action and arguments the approval covered, and when.
How an agent ends up with access it was never granted
Most over-reach traces back to four configuration patterns. The Slack app requests broader OAuth scopes than the task needs. The agent runs on a user token, which inherits the installing user's access rather than the agent's intended scope. A single bot token is shared across several agents, so each one holds the union of what any of them needs. Or the MCP server exposes search and history-read tools that accept arbitrary arguments and perform no per-request check.
The last pattern is a confused deputy. OWASP's MCP guidance describes the MCP server executing actions with its own, often broad, privileges instead of the requesting user's permissions. When the agent can pass any conversation identifier or search query to a server like that, the server's reach becomes the agent's reach.
There are two further risks. Prompt injection can encode sensitive data into ordinary-looking tool calls such as search queries, so arguments need inspection as well as results. And content returned from one conversation can leak into other tasks, users or agents if context is not scoped, which OWASP lists as MCP10, Context Injection and Over-Sharing. Slack permissions address the first set of causes. They do not address these.
Layer 1: Slack app and token configuration
Start with identity. Give each agent instance its own Slack app installation and bot token, and avoid user tokens for autonomous agents, since a user token carries the installing person's reach. Do not share a token between agents. NIST-hosted material notes that credentials can propagate across task boundaries and agents, allowing access beyond the original grant, so each credential should have one holder and one purpose.
Next, scopes. OWASP advises requesting the narrowest scope available, for example read-only rather than modify or full access. Apply the same reasoning to Slack by reviewing every history scope for public channels, private channels, direct messages and group direct messages, and the search read scope. Remove any the task does not need. If an agent summarizes one support channel, it has no reason to hold scopes that cover direct messages.
Then membership. Add the app only to the conversations it is meant to serve, and test what the token can actually return rather than assuming the scope list tells the whole story. Finally, bind tokens to their intended audience. The MCP server should reject tokens not issued for it and should never pass its own access token to an upstream API. Prefer time-bounded grants over standing ones.
Layer 2: MCP server tool exposure
The tool list is an access-control decision. OWASP advises giving agents the minimum tools required and limiting each tool's functionality, for example to read-only. For a Slack agent, that usually means deciding whether it needs search or channel history at all. A tool that posts a reply to a known channel is a much smaller risk surface than one that reads history from any channel.
Where a read tool is needed, restrict its parameters at the server. Replace free-form conversation identifiers with a fixed list of granted channel IDs, cap the number of messages returned per call, and constrain the time range. Treat search as the highest-risk tool, because a query reaches across conversations and can also carry exfiltrated data.
Maintain one tool policy per agent instance, and keep separate tool sets for different trust levels. If an agent delegates to sub-agents or downstream services, scopes should narrow at each hop so no downstream party holds more authority than its parent. The tradeoff is operational. Narrow, per-agent tool sets mean more configuration to maintain and less flexibility for the agent, which is the intended effect.
Layer 3: policy enforced in the execution path
Slack scopes and tool allowlists are static. They define what the agent could do, not what it asks for on a given call or what comes back. OWASP's agent guidance is explicit that authorization should be enforced in the execution component, outside the agent's context, because anything inside the model's context can be influenced by injected content. OWASP also names policy checks enforced at execution time as an option, to be selected according to risk.
In practice, the enforcement point sits between the agent and the MCP server and evaluates each tool call twice. Before the call, it checks the tool name, the channel ID and the query text against the agent's policy. After the call, it inspects what is returned to the model. The outcomes are:
Allow: the call matches the granted conversations and passes through.
Redact: the call is permitted, but sensitive fields in the returned content are removed before the model sees them.
Block: the call targets a conversation outside the grant, or the content should not reach the model at all.
Escalate: a sensitive read is held for human approval. The approval should be bound to the specific action and arguments and should not be reusable for a different request.
Rate limits add a further check, since a burst of history reads is a signal worth acting on. Trussed enforces policy in the execution path across MCP servers and tool calls, with these outcomes: allow, redact, block, rate limit and escalate for human approval. Enforcement happens at runtime, not in review after the fact. Because the decision is made on each call, it also produces the evidence described below.
Putting the layers together
No single layer is sufficient. Slack-side scoping limits what a credential can reach, but a user token or an over-scoped bot token reaches too far. Tool allowlists reduce the surface, but a retained search or read tool still accepts whatever arguments the model produces. Runtime enforcement catches those arguments and the returned content, but it works best when the layers beneath it are already narrow, so denials are rare and meaningful.
A practical sequence is to inventory every Slack-connected agent and the token each one uses, replace shared or user tokens with dedicated bot identities, strip scopes and tools the task does not need, then add per-call policy with human approval for sensitive reads. Test the result with adversarial inputs before deployment, including content from conversations that the agent treats as untrusted. For regulated enterprises, Trussed produces audit-ready evidence from enforcement across these tool calls, but the layered approach above is useful whichever enforcement mechanism you choose.
Three control layers for a Slack MCP agent
Slack app and token
Dedicated identity, narrow scopes, limited channel membership.
MCP server tool exposure
Tool allowlist, read-only where possible, validated parameters.
Runtime policy on tool calls
Allow, redact, block or escalate each request and response.
Enforce policy on every Slack tool call
See how policy in the execution path allows, redacts, blocks or escalates MCP tool calls and produces audit-ready evidence.
Explore Agent and Tool-Call EnforcementHow does your AI governance program compare?
See where your program has gaps in less than 2 minutes.