fix(slack): fail closed for interactive approval callbacks#33280
Conversation
|
Verified: this correctly consolidates the authorization checks from both Key correctness observations:
Test coverage is thorough — 8 new tests covering: no-allowlist denial, global allowlist permit/mismatch, slash-confirm auth, and runner-auth-first fallback. LGTM. |
|
Thanks for catching this on a real exploit path — independent confirmation from several contributors is what got it prioritized. The fail-open is being fixed in #41226 (open, pending review), a cross-adapter salvage that closes the same bug on Slack, Feishu, and Discord in one PR. For the Slack side we picked #33844 by @Dusk1e as canonical because it mirrors Telegram's Your fix is correct on the security logic, but Holding this open until #41226 is reviewed/merged rather than closing it now — the credit stands either way. |
|
Closing — the fail-open is now fixed on main via PR #41226 (merged: commits a317e54 / 410cb74 (Slack), 3fa15b3 (Feishu), f6f3636 (Discord)). The Slack side landed @Dusk1e's #33844 as canonical (delegates to the gateway runner's central auth, matching the Telegram precedent). Thanks again for the report and the fix — your contribution is credited in #41226. |
Summary
Fix Slack interactive approval authorization so Block Kit callbacks cannot resolve gated prompts unless the clicking user is authorized.
Slack approval and slash-confirm button handlers bypass the normal gateway message dispatch path, so they must enforce authorization locally. The previous callback checks only consulted
SLACK_ALLOWED_USERSwhen it was non-empty, which made an empty platform allowlist behave like allow-all for button clicks.This PR adds a shared Slack interactive auth helper that:
GatewayRunner._is_user_authorized()when availableSLACK_ALLOWED_USERS/GATEWAY_ALLOWED_USERSSecurity Impact
This closes an external-surface auth gap where an unauthorized Slack user who could see a Block Kit approval prompt could click an approval or slash-confirm button and resolve the pending action.
Affected surfaces:
This aligns Slack callbacks with the gateway trust model: session IDs and callback payloads are routing data, not authorization.
Tests
uv --cache-dir .uv-cache run --with pytest --with pytest-asyncio pytest -o addopts= tests/gateway/test_slack_approval_buttons.py -q
uv --cache-dir .uv-cache run --with pytest --with pytest-asyncio pytest -o addopts= tests/gateway/test_slack.py tests/gateway/test_slack_mention.py tests/gateway/test_slack_channel_skills.py tests/gateway/test_slack_approval_buttons.py -q
uv --cache-dir .uv-cache run --with pytest --with pytest-asyncio pytest -o addopts= tests/gateway/test_unauthorized_dm_behavior.py tests/gateway/test_allowlist_startup_check.py -q
uv --cache-dir .uv-cache run --with ruff ruff check gateway/platforms/slack.py tests/gateway/test_slack_approval_buttons.py
git diff --check
Results:
Slack approval tests: 29 passed
Full Slack gateway test set: 281 passed
Gateway allowlist tests: 34 passed
Ruff: passed
Diff check: passed