fix(discord): DISCORD_ALLOW_BOTS=mentions/all works without DISCORD_ALLOWED_USERS#11606
Merged
Conversation
…RD_ALLOWED_USERS Fixes #4466. Root cause: two sequential authorization gates both independently rejected bot messages, making DISCORD_ALLOW_BOTS completely ineffective. Gate 1 — `discord.py` `on_message`: _is_allowed_user ran BEFORE the bot filter, so bot senders were dropped before the DISCORD_ALLOW_BOTS policy was ever evaluated. Gate 2 — `gateway/run.py` _is_user_authorized: The gateway-level allowlist check rejected bot IDs with 'Unauthorized user: <bot_id>' even if they passed Gate 1. Fix: gateway/platforms/discord.py — reorder on_message so DISCORD_ALLOW_BOTS runs BEFORE _is_allowed_user. Bots permitted by the filter skip the user allowlist; non-bots are still checked. gateway/session.py — add is_bot: bool = False to SessionSource so the gateway layer can distinguish bot senders. gateway/platforms/base.py — expose is_bot parameter in build_source. gateway/platforms/discord.py _handle_message — set is_bot=True when building the SessionSource for bot authors. gateway/run.py _is_user_authorized — when source.is_bot is True AND DISCORD_ALLOW_BOTS is 'mentions' or 'all', return True early. Platform filter already validated the message at on_message; don't re-reject. Behavior matrix: | Config | Before | After | | DISCORD_ALLOW_BOTS=none (default) | Blocked | Blocked | | DISCORD_ALLOW_BOTS=all | Blocked | Allowed | | DISCORD_ALLOW_BOTS=mentions + @mention | Blocked | Allowed | | DISCORD_ALLOW_BOTS=mentions, no mention | Blocked | Blocked | | Human in DISCORD_ALLOWED_USERS | Allowed | Allowed | | Human NOT in DISCORD_ALLOWED_USERS | Blocked | Blocked | Co-authored-by: Hermes Maintainer <hermes@nousresearch.com>
Six test cases covering: - DISCORD_ALLOW_BOTS=mentions + bot not in DISCORD_ALLOWED_USERS → authorized - DISCORD_ALLOW_BOTS=all + bot not in DISCORD_ALLOWED_USERS → authorized - DISCORD_ALLOW_BOTS=none → bots still rejected (preserves security) - DISCORD_ALLOW_BOTS unset → same as 'none' - Humans still checked against allowlist even with allow_bots=all - Bot bypass is Discord-specific — doesn't leak to other platforms Guards against a regression where the is_bot bypass in _is_user_authorized gets moved, removed, or accidentally extended to other platforms.
This was referenced Apr 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvage of PR #4477 by @gnanam1990 with @gnanam1990 authorship preserved on the core fix commit.
Fixes #4466 (@alanjds).
Problem
DISCORD_ALLOW_BOTS=mentionsand=allwere completely ineffective. Two sequential authorization gates both rejected bot messages:on_messageingateway/platforms/discord.pyran_is_allowed_userBEFORE the bot filter._is_user_authorizedingateway/run.pyrejected bot IDs at the gateway level withUnauthorized user: <bot_id>even if a bot somehow made it past Gate 1.Triggered by the #4466 reporter when a Cloudflare Worker webhook posting Notion events to Discord was silently ignored despite
DISCORD_ALLOW_BOTS=mentionsbeing set.Fix
gateway/platforms/discord.py— reorderon_messageso the bot filter runs BEFORE the user allowlist. Bots permitted byDISCORD_ALLOW_BOTSskip the human allowlist; non-bots are still checked.gateway/session.py— addis_bot: bool = FalsetoSessionSource.gateway/platforms/base.py— exposeis_botinbuild_source.gateway/platforms/discord.py_handle_message— setis_bot=Truefor bot authors.gateway/run.py_is_user_authorized— whensource.is_botis True ANDDISCORD_ALLOW_BOTSismentions/all, return True early. Platform already validated; don't re-reject.Behavior matrix
DISCORD_ALLOW_BOTS=none(default)DISCORD_ALLOW_BOTS=allDISCORD_ALLOW_BOTS=mentions+ @mentionDISCORD_ALLOW_BOTS=mentions, no mentionDISCORD_ALLOWED_USERSWhat we dropped from the original PR
PR #4477 bundled an unrelated
agent/redact.pychange fixing issue #4367 (lowercase Python variable false-positive redaction). Correct fix, but out of scope for this PR. Issue #4367 remains open for separate triage — the redact.py patch from @gnanam1990 is still a candidate for salvage there.Test plan
tests/gateway/test_discord_bot_auth_bypass.py— 6 regression cases covering the full behavior matrix + platform isolation (bypass doesn't leak to Telegram etc.): all pass.pytest tests/gateway/ -k discord→ 229 passed (no change from baseline).pytest tests/gateway/ -k 'auth or allow or unauthor'→ 134 passed, 1 skipped.Commits
e386ace7— fix(discord): DISCORD_ALLOW_BOTS=... without DISCORD_ALLOWED_USERS (@gnanam1990, authorship preserved; manually applied since cherry-pick conflicted with the newer multi-agent filtering code on main)b5db3735— test(discord): regression guard for DISCORD_ALLOW_BOTS auth bypass (ours — 6 new test cases)af25ea11— chore(release): map @gnanam1990 to AUTHOR_MAP