Summary
The Slack Block-Kit approval handler _handle_approval_action in gateway/platforms/slack.py authorizes approval-button clicks (hermes_approve_once/session/always, hermes_deny) by checking SLACK_ALLOWED_USERS. The check is wrapped in if allowed_csv: — so when the env var is unset (the default), the entire authorization block is skipped and execution falls through to processing the approval. Any workspace member who can see the approval message can click any button, including "Approve always".
The in-code comment at the check explicitly notes that "Button clicks bypass the normal message auth flow in gateway/run.py, so we must check here as well" — yet that very check is disabled by default. (Contrast: the Telegram equivalent was fixed to fail closed in #24457; the Slack path still fails open.)
Affected code (current main, ef3a650f05d2)
gateway/platforms/slack.py:2908 — _handle_approval_action:
async def _handle_approval_action(self, ack, body, action) -> None:
await ack()
...
user_id = body.get("user", {}).get("id", "")
# Only authorized users may click approval buttons. Button clicks
# bypass the normal message auth flow in gateway/run.py, so we must
# check here as well.
allowed_csv = os.getenv("SLACK_ALLOWED_USERS", "").strip()
if allowed_csv: # ← unset (default) ⇒ block skipped entirely
allowed_ids = {uid.strip() for uid in allowed_csv.split(",") if uid.strip()}
if "*" not in allowed_ids and user_id not in allowed_ids:
logger.warning("[Slack] Unauthorized approval click by %s (%s) — ignoring", ...)
return
# ... approval is processed here regardless of user identity ...
Unlike the patched Telegram handler, there is no upstream _is_user_authorized runner check on this path — if allowed_csv: is the only gate.
Exploitation
- Operator runs the Slack gateway with
SLACK_ALLOWED_USERS unset (default; not present in example configs).
- The agent posts an approval prompt for a dangerous action (via a legitimate request or prompt-injection).
- Any workspace member in the channel (including a guest) taps Approve always.
_handle_approval_action skips the auth block and persists the approval — granting unattended approval of every future command matching that pattern (written to the operator's ~/.hermes/config.yaml command_allowlist).
Impact
Privilege/authorization bypass enabling persistent allowlisting of dangerous commands by any channel member. CWE-1188 (Insecure Default), CWE-305 (Auth Bypass by Primary Weakness). High.
Suggested remediation
Fail closed: when SLACK_ALLOWED_USERS is unset, deny by default and require an explicit SLACK_ALLOWED_USERS=* opt-in for no-restriction mode (mirror the Telegram fix from #24457 — GATEWAY_ALLOW_ALL_USERS gate / _is_user_authorized runner path). Refuse to register the Block-Kit action handlers when no allowlist is configured.
Prior private disclosure & status
Reported privately via GitHub Security Advisory (GHSA-jg5x-hmg9-2q4c, "Slack Block-Kit approval handler fails open when SLACK_ALLOWED_USERS is unset", rated High). As of 2026-06-01 the advisory remains in triage with no action taken, and the fail-open still reproduces on current main (ef3a650f05d2) — note the analogous Telegram issue was fixed (#24457), but the Slack path was not. Filing publicly so it has a tracked record.
Summary
The Slack Block-Kit approval handler
_handle_approval_actioningateway/platforms/slack.pyauthorizes approval-button clicks (hermes_approve_once/session/always,hermes_deny) by checkingSLACK_ALLOWED_USERS. The check is wrapped inif allowed_csv:— so when the env var is unset (the default), the entire authorization block is skipped and execution falls through to processing the approval. Any workspace member who can see the approval message can click any button, including "Approve always".The in-code comment at the check explicitly notes that "Button clicks bypass the normal message auth flow in gateway/run.py, so we must check here as well" — yet that very check is disabled by default. (Contrast: the Telegram equivalent was fixed to fail closed in #24457; the Slack path still fails open.)
Affected code (current
main,ef3a650f05d2)gateway/platforms/slack.py:2908—_handle_approval_action:Unlike the patched Telegram handler, there is no upstream
_is_user_authorizedrunner check on this path —if allowed_csv:is the only gate.Exploitation
SLACK_ALLOWED_USERSunset (default; not present in example configs)._handle_approval_actionskips the auth block and persists the approval — granting unattended approval of every future command matching that pattern (written to the operator's~/.hermes/config.yamlcommand_allowlist).Impact
Privilege/authorization bypass enabling persistent allowlisting of dangerous commands by any channel member. CWE-1188 (Insecure Default), CWE-305 (Auth Bypass by Primary Weakness). High.
Suggested remediation
Fail closed: when
SLACK_ALLOWED_USERSis unset, deny by default and require an explicitSLACK_ALLOWED_USERS=*opt-in for no-restriction mode (mirror the Telegram fix from #24457 —GATEWAY_ALLOW_ALL_USERSgate /_is_user_authorizedrunner path). Refuse to register the Block-Kit action handlers when no allowlist is configured.Prior private disclosure & status
Reported privately via GitHub Security Advisory (
GHSA-jg5x-hmg9-2q4c, "Slack Block-Kit approval handler fails open whenSLACK_ALLOWED_USERSis unset", rated High). As of 2026-06-01 the advisory remains intriagewith no action taken, and the fail-open still reproduces on currentmain(ef3a650f05d2) — note the analogous Telegram issue was fixed (#24457), but the Slack path was not. Filing publicly so it has a tracked record.