hermes - 💡(How to fix) Fix Feature: opt-in webhook bypass for DISCORD_ALLOW_BOTS — allow operator-initiated probes without weakening bot-loop guard

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

Concrete example: a persona-regression test harness that wants to send a probe to each bot, see if the bot still produces lane-correct output, and grade against expected voice markers. The natural approach is webhook posts (operator-initiated, distinct from bot-to-bot chatter), but gateway/platforms/discord.py treats webhook messages identically to bot messages because discord.py's Message.author.bot returns True for webhook senders.

Fix Action

Fix / Workaround

Workaround used in our fleet

Until a built-in mechanism lands, we're applying a local source patch + adding the webhook user-IDs to DISCORD_ALLOWED_USERS manually. Documented in ~/brain/incidents/persona-harness-paused-2026-05-28.md for future-us.

The local patch is a maintenance burden (lost on every uv tool upgrade hermes-agent) — hence the request for an upstream solution.

Code Example

_is_webhook = getattr(message, "webhook_id", None) is not None
_treat_wh_as_operator = os.getenv("DISCORD_TREAT_WEBHOOKS_AS_OPERATOR", "false").lower() in ("true", "1", "yes")

if _is_webhook and _treat_wh_as_operator:
    pass  # webhook = operator-initiated, bypass bot filter
elif getattr(message.author, "bot", False):
    # ... existing ALLOW_BOTS logic unchanged
RAW_BUFFERClick to expand / collapse

Use case

Operators running a multi-Hermes fleet with DISCORD_ALLOW_BOTS=none (the safest setting against bot-to-bot loops) currently have no clean way to send legitimate operator-initiated probes to their own bots.

Concrete example: a persona-regression test harness that wants to send a probe to each bot, see if the bot still produces lane-correct output, and grade against expected voice markers. The natural approach is webhook posts (operator-initiated, distinct from bot-to-bot chatter), but gateway/platforms/discord.py treats webhook messages identically to bot messages because discord.py's Message.author.bot returns True for webhook senders.

So with DISCORD_ALLOW_BOTS=none:

  • ✅ Emergent bot-to-bot loops are blocked (desired)
  • ❌ Operator-initiated webhook probes are also blocked (undesired)

Proposal

Add a new env var, DISCORD_TREAT_WEBHOOKS_AS_OPERATOR (default false for back-compat), that — when true — causes webhook messages to bypass both the DISCORD_ALLOW_BOTS check and the DISCORD_ALLOWED_USERS allowlist.

Rationale: webhooks are operator-infrastructure. Creating one requires MANAGE_WEBHOOKS in the channel; the URL is a capability secret the operator controls. They're closer to "the operator running a curl from a script" than "an emergent bot in the channel."

Proposed code change (small)

In gateway/platforms/discord.py, around the existing if getattr(message.author, "bot", False) check:

_is_webhook = getattr(message, "webhook_id", None) is not None
_treat_wh_as_operator = os.getenv("DISCORD_TREAT_WEBHOOKS_AS_OPERATOR", "false").lower() in ("true", "1", "yes")

if _is_webhook and _treat_wh_as_operator:
    pass  # webhook = operator-initiated, bypass bot filter
elif getattr(message.author, "bot", False):
    # ... existing ALLOW_BOTS logic unchanged

And in gateway/run.py _is_user_authorized, treat webhook-source messages as authorized when the env var is set.

Workaround used in our fleet

Until a built-in mechanism lands, we're applying a local source patch + adding the webhook user-IDs to DISCORD_ALLOWED_USERS manually. Documented in ~/brain/incidents/persona-harness-paused-2026-05-28.md for future-us.

The local patch is a maintenance burden (lost on every uv tool upgrade hermes-agent) — hence the request for an upstream solution.

Why opt-in (not always-bypass)

Security-conscious deployments may want webhooks to be subject to the same scrutiny as bots. Opt-in via env var preserves their current behavior. Operators who explicitly opt in are accepting that anyone with their webhook URLs can post bypass.

Happy to open a PR if the maintainers agree with the design.

Related

  • Issue #6440 (webhook RCE concern) — relevant security context for webhook handling
  • Issue #34034 (v0.15 missing plugin.yaml — different bug, same code area)
  • Hermes is otherwise extensively configurable for bot-source filtering; webhook is the one gap.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING