Slack: Deny Read/Search/Summarize of Sensitive Channels
Blocks read, search, and summarize operations that target a configurable set of "sensitive" Slack channels.
- Direction
- ingress
- Rego package
slack.ingress.deny_sensitive_channel_read- App
- slack
- Bundles
- slacksoc2hipaagdpr-ccpa
- Published
- Minimum gateway
- 1.0.0b24
- Schema version
- 1.0.0
- Checksum
sha256:be0ecf31a6f6908191cd28f537364984fc5771a0c39a9990d141094155b8e47b
slackaccess-controldata-protectioningresssoc2hipaagdpr-ccpaiso27001-nist
What this policy does
Direction: ingress (tool_pre_invoke)
Default: allow, with a targeted deny on sensitive-channel reads
Package: slack.ingress.deny_sensitive_channel_read
What it does
Blocks read, search, and summarize operations that target a configurable set of "sensitive" Slack channels. Every other Slack tool — and every channel not in the set — passes through untouched. A blocked call returns a clear denial reason instead of returning channel contents.
The set of sensitive channel IDs is configured once at the top of the Rego
(sensitive_channel_ids).
Compliance alignment
What the fence supports depends on what you put behind it — populate
sensitive_channel_ids with the channels that carry the regulated content.
- HIPAA §164.502(b) / §164.514(d) — supports minimum-necessary access when PHI-bearing channels (care coordination, patient escalations) are in the set.
- HIPAA §164.308(a)(4) — supports information access management: a technical restriction on which conversations the agent may read.
- SOC 2 C1.1 — supports identification and protection of confidential information (deal rooms, legal, incident channels).
- PCI DSS 7.2.6 — supports restricting programmatic query access to cardholder data when channels discussing CHD are in the set.
- GDPR Art. 9 / CPRA §1798.121 — supports limiting access to special-category data and sensitive personal information (HR, health, works-council channels).
- ISO 27001 A.8.3 — information access restriction on the agent channel.
Why ingress
The risk is reading content out of a protected channel, and that intent is fully visible in the request (the tool name plus the channel argument). Denying at ingress stops the read before it reaches Slack, so no protected message, thread, or summary is ever returned to the caller.
How it matches
A call is denied only when all three conditions hold:
- Slack-server scoping. The first hyphen-separated segment of the tool name
starts with
slack, so the policy works regardless of how the Slack MCP server is named on a given gateway (slack-...,slack-prod-...,slack-mcp-...). - Restricted-tool detection. The (lowercased) tool name ends with one of
the known suffixes across three operation families — channel history/replies
reads, search, and summarize — with
-,_, and concatenated naming variants covered. - Sensitive-channel detection. The channel is matched by ID against the
configured set, both as a direct argument (
channel,channel_id,channelId) and as a substring of search-query arguments (query,q), so channel-mention syntax inside a query (e.g.in:<#C…>or<#C…|team-name>) is also caught.
Matching is on channel IDs, not names, because these tools receive resolved
channel IDs at call time — a name-based approach does not fire. ID comparisons
are case-sensitive, mirroring Slack's own behavior. Confirm the exact tool and
argument names your gateway emits with the dump-input debug technique, and
extend restricted_tool_suffixes or the channel-arg lookups if your Slack MCP
server differs.
Examples
Denied (reading a sensitive channel's history)
{
"input": {
"action": "tool_pre_invoke",
"resource": { "name": "slack-mcp-conversations-history", "type": "tool" },
"payload": {
"name": "slack-mcp-conversations-history",
"args": { "channel": "SLACK_CHANNEL_ID", "limit": 50 }
}
}
}
allow = false,
reason = "Reading, searching, or summarizing this Slack channel is not permitted via this gateway. ...".
Allowed (reading a non-sensitive channel)
{
"input": {
"action": "tool_pre_invoke",
"resource": { "name": "slack-mcp-conversations-history", "type": "tool" },
"payload": {
"name": "slack-mcp-conversations-history",
"args": { "channel": "C0PUBLIC001", "limit": 50 }
}
}
}
allow = true, no reason.
Configuration
Edit the sensitive_channel_ids set at the top of the policy. The shipped value
(SLACK_CHANNEL_ID) is a placeholder — replace it with your real Slack
channel IDs (uppercase, case-sensitive, e.g. C0B5LHR8DQV).
Composition
Single-purpose and default allow := true, so it composes cleanly with other
Slack ingress policies (e.g. block-secrets,
deny-channel-creation) on the same
pipeline.
Known limitations
- ID-based, not name-based. The policy keys off channel IDs; it does not resolve channel names to IDs. Populate the ID set with the real IDs of the channels you need to protect.
- Suffix list, not an exhaustive catalog. Only the tool shapes listed in
restricted_tool_suffixesare matched. Add the suffix for any additional read/search/summarize tool your Slack MCP server exposes. - No identity-based exemptions. All callers are treated the same. To allow a
specific break-glass user, gate a separate
allow ifbranch oninput.subject.claims.
Compliance note. This policy supports alignment with the cited framework controls on the MCP path only. No policy or bundle makes an organization compliant with any framework; web-UI, native-API, and in-app access are outside the gateway's reach by design. Validate against your own compliance program before relying on it.
Policy source (Rego)
package slack.ingress.deny_sensitive_channel_read
# Default-allow: only deny restricted operations on the configured channel IDs.
default allow := true
# -----------------------------------------------------------------------------
# CONFIG: Sensitive Slack channel IDs. Edit to add or remove. Slack channel
# IDs are uppercase alphanumeric and case-sensitive (e.g. "C0B5LHR8DQV").
# -----------------------------------------------------------------------------
sensitive_channel_ids := {
"SLACK_CHANNEL_ID", #placeholder value, replace with your Slack channel_id
}
# -----------------------------------------------------------------------------
# Slack-server detection: any tool whose first hyphen-separated segment starts
# with "slack" (slack-, slack3-, slack-prod-, etc.).
# -----------------------------------------------------------------------------
is_slack_tool if {
name := lower(input.resource.name)
server_name := split(name, "-")[0]
startswith(server_name, "slack")
}
# -----------------------------------------------------------------------------
# Restricted-tool detection — covers read (channel history / replies), search,
# and summarize operation families. Suffix matching tolerates different MCP
# naming conventions across implementations.
# -----------------------------------------------------------------------------
restricted_tool_suffixes := {
# ---- Read: channel history / messages ----
"-conversations-history",
"-conversations_history",
"-conversationshistory",
"-channel-history",
"-channel_history",
"-channelhistory",
"-get-history",
"-get_history",
"-gethistory",
"-get-messages",
"-get_messages",
"-getmessages",
"-read-channel",
"-read_channel",
"-readchannel",
# ---- Read: replies / threads ----
"-conversations-replies",
"-conversations_replies",
"-conversationsreplies",
"-get-replies",
"-get_replies",
"-getreplies",
"-thread-history",
"-thread_history",
"-threadhistory",
# ---- Search ----
"-search-messages",
"-search_messages",
"-searchmessages",
"-search-all",
"-search_all",
"-searchall",
"-search-files",
"-search_files",
"-searchfiles",
# ---- Summarize ----
"-summarize-channel",
"-summarize_channel",
"-summarizechannel",
"-channel-summary",
"-channel_summary",
"-channelsummary",
"-summarize-conversation",
"-summarize_conversation",
"-summarizeconversation",
"-summarize",
"-summary",
}
is_restricted_tool if {
is_slack_tool
name := lower(input.resource.name)
some suffix in restricted_tool_suffixes
endswith(name, suffix)
}
# -----------------------------------------------------------------------------
# Sensitive-channel-ID detection — match the channel arg against the
# configured ID set, OR find an ID inside a search query.
#
# Slack channel IDs are uppercase letter+digit strings (e.g. C0B5LHR8DQV).
# Comparisons are exact (case-sensitive) since the Slack API itself preserves
# case.
# -----------------------------------------------------------------------------
# Direct channel arg shapes
channel_id_is_sensitive if {
v := object.get(input.payload.args, "channel", "")
sensitive_channel_ids[v]
}
channel_id_is_sensitive if {
v := object.get(input.payload.args, "channel_id", "")
sensitive_channel_ids[v]
}
channel_id_is_sensitive if {
v := object.get(input.payload.args, "channelId", "")
sensitive_channel_ids[v]
}
# Search-query substring check — catches Slack channel-mention syntax inside
# queries (e.g. 'in:<#C0B5LHR8DQV>' or '<#C0B5LHR8DQV|fin-team>').
channel_id_is_sensitive if {
q := object.get(input.payload.args, "query", "")
is_string(q)
some id in sensitive_channel_ids
contains(q, id)
}
channel_id_is_sensitive if {
q := object.get(input.payload.args, "q", "")
is_string(q)
some id in sensitive_channel_ids
contains(q, id)
}
# -----------------------------------------------------------------------------
# Deny rule
# -----------------------------------------------------------------------------
allow := false if {
is_restricted_tool
channel_id_is_sensitive
}
reason := "Reading, searching, or summarizing this Slack channel is not permitted via this gateway. Contact your InfoSec team if this needs to change." if not allow Canonical source: policy.md on GitHub · raw · raw on this site (.md)
Used in these guides
Related policies
Airtable: Redact PII in Record Reads
Scans the responses of the Airtable record-read tools — the calls that return row fields values — and rewrites high-confidence PII shapes to a fixed…
Asana: Redact PII in Task & Comment Reads
On the Asana MCP read path, this transform scans the free-text business fields that ride back in task, comment/story, and status-update responses — notes,…
BigQuery: Redact PII in Query Results
Scans the content returned by BigQuery's result-returning tools and rewrites high-confidence PII shapes to fixed, non-recoverable redaction tokens before the…
Block Agent Email to External Recipients
Blocks agent-initiated Microsoft 365 email sends when any recipient address falls outside a corporate-domain allowlist.
Block BigQuery Exfiltration and Cross-Project Writes
Inspects the raw GoogleSQL string carried by BigQuery SQL tools and denies any statement that moves data out of the tenant's own project — even when the call…
bigqueryguard-warehouse-exportingresssqlexfiltrationsoc2pci-dssgdpr-ccpa
Block Bulk Export & External Staging (Snowflake)
Blocks Snowflake SQL-execution tool calls whose query text moves whole tables off the Snowflake perimeter — bulk export to cloud storage or a stage, and…
snowflakeguard-warehouse-sqlexportexfiltrationingresssoc2pci-dssgdpr-ccpa