Skip to content

fix(discord): DISCORD_ALLOW_BOTS=mentions/all now works without DISCORD_ALLOWED_USERS#4477

Closed
gnanam1990 wants to merge 2 commits into
NousResearch:mainfrom
gnanam1990:fix/discord-allow-bots-4466
Closed

fix(discord): DISCORD_ALLOW_BOTS=mentions/all now works without DISCORD_ALLOWED_USERS#4477
gnanam1990 wants to merge 2 commits into
NousResearch:mainfrom
gnanam1990:fix/discord-allow-bots-4466

Conversation

@gnanam1990

Copy link
Copy Markdown
Contributor

Root Cause

Two sequential authorization gates both independently blocked bot messages, making DISCORD_ALLOW_BOTS completely ineffective:

Gate 1 — discord.py on_message (line ~552 on main):

# _is_allowed_user ran BEFORE the bot filter
if not self._is_allowed_user(str(message.author.id)):
    return  # bot dropped here — DISCORD_ALLOW_BOTS never reached

if getattr(message.author, "bot", False):
    allow_bots = os.getenv("DISCORD_ALLOW_BOTS", "none")
    ...  # never reached for bots not in DISCORD_ALLOWED_USERS

Gate 2 — gateway/run.py _is_user_authorized:
Even if a bot somehow passed Gate 1, the gateway-level allowlist check would reject it, producing the WARNING gateway.run: Unauthorized user: <bot_id> message reported in the issue.

Fix

gateway/platforms/discord.py — reorder on_message checks so DISCORD_ALLOW_BOTS runs before _is_allowed_user. Bots that pass the bot filter (mentions/all) skip the user allowlist entirely; non-bots are still checked as before.

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 and pass it through to SessionSource.

gateway/platforms/discord.py _handle_message — set is_bot=True for bot authors when building SessionSource.

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).

Result

Config Before After
DISCORD_ALLOW_BOTS=none (default) Bots blocked ✓ Bots blocked ✓
DISCORD_ALLOW_BOTS=all Bots blocked ✗ Bots allowed ✓
DISCORD_ALLOW_BOTS=mentions + bot @mentions Hermes Bots blocked ✗ Bots allowed ✓
DISCORD_ALLOW_BOTS=mentions + no mention Bots blocked ✓ Bots blocked ✓
Human users in DISCORD_ALLOWED_USERS Allowed ✓ Allowed ✓
Human users NOT in DISCORD_ALLOWED_USERS Blocked ✓ Blocked ✓

Fixes #4466

🤖 Generated with Claude Code

gnanam1990 and others added 2 commits April 1, 2026 23:33
…ing lowercase variables

The _ENV_ASSIGN_RE pattern was compiled with re.IGNORECASE, causing it to
match lowercase variable assignments like `token = await ...` and
`before_tokens = response.usage` as if they were secret environment variables.

This caused two reported bugs:
- NousResearch#4367: Python variable assignments (before_tokens, api_key, my_token)
  being incorrectly redacted in logs and tool output
- NousResearch#4451: TypeScript/JS `await` keyword corrupted to `***` in patch tool output
  because `const token = await getToken()` matched the pattern, replacing
  `await` with `***` and stripping the surrounding whitespace

Fix: remove re.IGNORECASE so only ALL-UPPERCASE env var names match.
Add (?:^|(?<=\s)) lookbehind to prevent the pattern from consuming
leading whitespace (e.g. `export SECRET=...` preserved correctly).

Adds regression tests covering both Python and TypeScript/JS cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…RD_ALLOWED_USERS

The _is_allowed_user() check in on_message ran before the DISCORD_ALLOW_BOTS
filter, so bot messages were silently dropped when the bot's user ID was not
in DISCORD_ALLOWED_USERS — before DISCORD_ALLOW_BOTS was ever consulted.

A second gate in _is_user_authorized() (gateway/run.py) then rejected the
same bots with "Unauthorized user" even when they passed the Discord-level
bot filter.

Fix:
- discord.py on_message: move DISCORD_ALLOW_BOTS check before _is_allowed_user
  so bots permitted by mentions/all bypass the user allowlist entirely
- session.py SessionSource: add is_bot: bool = False field
- base.py build_source: expose is_bot parameter and pass it through
- discord.py _handle_message: set is_bot=True for bot authors on the source
- run.py _is_user_authorized: skip the user allowlist for Discord bot senders
  when DISCORD_ALLOW_BOTS is mentions or all

Fixes NousResearch#4466

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@teknium1

Copy link
Copy Markdown
Contributor

Merged via #11606#11606

Your core fix commit e56569ae was applied to current main with your authorship preserved (the on_message area had conflicts with newer multi-agent filtering code on main, so we applied it manually via git commit --author=... rather than git cherry-pick). Added regression tests (tests/gateway/test_discord_bot_auth_bypass.py) covering the full 6-row behavior matrix from your PR body.

We dropped the agent/redact.py commit (09b78c27) — that fix is correct but addresses a separate issue (#4367, lowercase Python variable redaction), so it's out of scope for this PR. #4367 is still open; if you'd like to submit that fix as its own PR we'd be happy to review and credit it — your original analysis there was sharp too.

Thanks for the thorough root-cause writeup and the precise code pointers — made this a fast review.

@teknium1 teknium1 closed this Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DISCORD_ALLOW_BOTS has no effect without also adding the bot to DISCORD_ALLOWED_USERS

2 participants