Skip to content

Security: Slack Block-Kit approval handler fails open when SLACK_ALLOWED_USERS is unset (any channel member can Approve-always) #36848

@dhyabi2

Description

@dhyabi2

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

  1. Operator runs the Slack gateway with SLACK_ALLOWED_USERS unset (default; not present in example configs).
  2. The agent posts an approval prompt for a dangerous action (via a legitimate request or prompt-injection).
  3. Any workspace member in the channel (including a guest) taps Approve always.
  4. _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 #24457GATEWAY_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/gatewayGateway runner, session dispatch, deliveryplatform/slackSlack app adaptertype/securitySecurity vulnerability or hardening

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions