Rightshold™ Sign up

Answers · MCP security

How do I treat Slack messages, tickets and logs that an MCP server returns as untrusted, and add write access safely?

Last updated

TL;DR: Anyone who can post in a channel, file a ticket, comment on an issue or get a string into a log can write text your agent will read, so every MCP server that returns that content is a prompt-injection path even when the server itself is honest. OWASP calls this indirect prompt injection: instructions hidden in external content that change what the model does. The model can't be relied on to ignore them, so put the controls around it: connect read-only first, give each write permission its own step with a confirmation, and don't let one session combine private data, untrusted content and a way to send data out (Simon Willison's lethal trifecta). The MCP specification (2026-07-28) says clients should ask the user to confirm sensitive operations, show tool inputs before calling the server, and validate tool results before passing them to the model. Then add write scopes one at a time, for example Slack's reactions:write before chat:write, and only after watching what the agent does with read access.

What should I check, step by step?

1. List who can write into each source: a public Slack channel, a shared Slack Connect channel, a support queue that takes email from customers, public GitHub issues and any log that records user input are all written by people outside your team. Treat that content as data from a stranger.

  1. Start read-only: run the GitHub MCP server with --read-only (write tools are skipped even if you name them with --tools) and only the --toolsets you need, and request only read scopes for other servers.
  2. Request the narrowest read scopes the task needs. Slack's MCP server maps tools to user-token scopes: searching public channels needs search:read.public, while search:read.private, search:read.im and search:read.mpim also open private channels and direct messages. Leave those out unless the task needs them.
  3. Filter where the server can: the GitHub MCP server's --lockdown-mode withholds public-repository content from authors without push access. GitHub says it is a best-effort filter, not an authorization boundary, so keep the other controls too.
  4. Add one write permission at a time, starting with the most reversible, and run it with confirmation on for a while before the next. For Slack, that could be reactions:write, then drafts reviewed by a person, then chat:write; canvases:write, channels:write and files:write each get their own step.
  5. Make every write ask first: in Claude Code, put write tools in an ask rule (for example mcp__slack__* in ask, specific read tools in allow). Rules are evaluated deny, then ask, then allow, so a broad ask or deny wins over a narrower allow.
  6. Break the trifecta per session: a session that reads public tickets shouldn't also hold a tool that posts to the internet or reads private channels. Split it into a read-and-summarize step and a separate act step that a person approves.
  7. Show the full arguments of any write before it runs, and flag writes the user didn't ask for, especially a message to a channel or person outside the task.

Why an honest MCP server can still inject

The server isn't the attacker here. A Slack or ticketing server faithfully returns what people wrote, and if one of those messages says to forward the thread somewhere or close every open ticket, the model sees it in the same context as your instructions.

What each control does and doesn't cover

Read-only mode stops the server from writing, but reading is the leak in many attacks: an agent that reads private data and has any other tool that can send data out can still leak it.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “Does this ticket or Slack message contain hidden text or instructions aimed at my agent before I pass it on?”

One-click setup

{
  "tool": "scan_text",
  "arguments": {
    "text": "<the ticket, Slack message or log line>"
  }
}

Rightshold scans text you send it and reports what is on record about MCP servers. It doesn't connect to your Slack, ticketing system or GitHub, grant or remove scopes, or enforce permissions in your MCP client.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'