Skip to content

fix(whatsapp): end-to-end allowlisted group intake for multi-member chats - #68844

Open
bhargav-forsyt wants to merge 1 commit into
NousResearch:mainfrom
bhargav-forsyt:fix/whatsapp-group-allowlist-e2e
Open

fix(whatsapp): end-to-end allowlisted group intake for multi-member chats#68844
bhargav-forsyt wants to merge 1 commit into
NousResearch:mainfrom
bhargav-forsyt:fix/whatsapp-group-allowlist-e2e

Conversation

@bhargav-forsyt

Copy link
Copy Markdown

What does this PR do?

Fixes the full path that makes allowlisted WhatsApp groups dead for anyone who is not also on the DM allowlist — the customer-support / multi-member group use case.

A message from a non-owner group member currently dies at up to three independent gates even when WHATSAPP_GROUP_ALLOWED_USERS contains that group's JID:

Layer Bug Effect
Baileys adapter _allow_from / _group_allow_from only read config.extra, never the documented env vars Wizard / .env-only installs run *_policy=allowlist with an empty set → every inbound silently dropped after the bridge queues it
Bridge DM sender allowlist (WHATSAPP_ALLOWED_USERS) applied to group participants Non-owner members never leave the Node process (allowlist_mismatch)
Gateway authz WHATSAPP_GROUP_ALLOWED_USERS not wired as a chat-scoped allowlist (unlike TELEGRAM_GROUP_ALLOWED_CHATS) Adapter-accepted group traffic still hits Unauthorized user for members not on the DM allowlist

Also forwards owner-typed (fromMe) group messages when WHATSAPP_FORWARD_OWNER_MESSAGES=true (personal-number bot) or WHATSAPP_MODE=self-chat, so operators can talk to the agent in groups. Default remains drop (from_me_group) for dedicated bot-number deployments.

Why one PR (not three): each layer alone still leaves the group looking dead. Reviewers cannot validate the customer-support path without all three. Pure classifiers are unit-tested so each gate stays reviewable in isolation.

Related open PRs (partial coverage — this supersedes the E2E gap)

Happy to close or coordinate if a maintainer prefers salvaging one of the above instead.

Related Issue

Related to #7269 (group members unauthorized). Complements the WhatsApp Cloud env-allowlist salvage (#58504 / #58448) for the Baileys path.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • plugins/platforms/whatsapp/adapter.py_resolve_allow_list_source() with key-presence semantics (explicit allow_from: [] stays deny-all; no silent widen via stale env). Falls back to WHATSAPP_ALLOWED_USERS / WHATSAPP_ALLOW_FROM and WHATSAPP_GROUP_ALLOWED_USERS / WHATSAPP_GROUP_ALLOW_FROM. Optional WHATSAPP_ALLOW_ALL_USERS* only when no config key present.
  • gateway/authz_mixin.py — map Platform.WHATSAPPWHATSAPP_GROUP_ALLOWED_USERS in both chat-allowlist maps; accept bare numeric group id or full @g.us JID.
  • scripts/whatsapp-bridge/dm_allowlist_scope.js — pure helper: DM sender allowlist is not applied to groups.
  • scripts/whatsapp-bridge/from_me_group_gate.js — pure helper: group fromMe forward rules (self-chat always; bot only with WHATSAPP_FORWARD_OWNER_MESSAGES; always drop status / /send echoes).
  • scripts/whatsapp-bridge/bridge.js — wire both helpers.
  • Tests: test_whatsapp_baileys_allowlist_env.py, test_whatsapp_group_chat_authz.py, dm_allowlist_scope.test.mjs, from_me_group_gate.test.mjs.

How to Test

  1. Env-only allowlists (adapter)
    ./scripts/run_tests.sh tests/gateway/test_whatsapp_baileys_allowlist_env.py
  2. Gateway group chat authz (any member in allowlisted @g.us)
    ./scripts/run_tests.sh tests/gateway/test_whatsapp_group_chat_authz.py
  3. Bridge pure gates
    cd scripts/whatsapp-bridge
    node --test dm_allowlist_scope.test.mjs from_me_group_gate.test.mjs allowlist.test.mjs owner_message_gate.test.mjs
    node --check bridge.js
  4. Existing suites still green
    ./scripts/run_tests.sh tests/gateway/test_whatsapp_group_gating.py tests/gateway/test_whatsapp_from_owner.py tests/gateway/test_whatsapp_cloud_allowed_users.py
  5. Manual E2E (optional)
    • WHATSAPP_MODE=bot
    • WHATSAPP_DM_POLICY=allowlist + WHATSAPP_ALLOWED_USERS=<owner phone only>
    • WHATSAPP_GROUP_POLICY=allowlist + WHATSAPP_GROUP_ALLOWED_USERS=<group JID>
    • Non-owner member texts the group → agent replies
    • Stranger DM still denied
    • With WHATSAPP_FORWARD_OWNER_MESSAGES=true, owner-typed group message is processed

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass (targeted WhatsApp / authz suites above — 66 Python + 24 Node)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Ubuntu 24.04 (Linux)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A (behavior matches already-documented env vars; no new keys)
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A (Node + Python pure logic, no OS-specific paths)
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Security / defaults

Path Before After
Env-only DM allowlist empty set → drop all honors WHATSAPP_ALLOWED_USERS
Explicit allow_from: [] + stale env could widen via or chain stays deny-all (key-presence)
Allowlisted group, non-owner member bridge and/or authz drop authorized
Non-allowlisted group drop drop
Stranger DM drop / pair per policy unchanged
Group fromMe (bot, flag off) drop drop (unchanged default)
Group fromMe (flag on / self-chat) drop forward + Python group gates

Screenshots / Logs

Local validation:

Python: 66 passed (baileys env, group authz, group gating, from_owner, cloud allowed users, lid resolution)
Node:   24 passed (dm_allowlist_scope, from_me_group_gate, allowlist, owner_message_gate)

…hats

Wizard/.env installs configure WHATSAPP_ALLOWED_USERS and
WHATSAPP_GROUP_ALLOWED_USERS, but three independent gates still dropped
messages after the bridge queued them:

1. Baileys adapter only read allowlists from config.extra (empty for
   env-only installs), so dm_policy/group_policy=allowlist ran with an
   empty set and silently rejected every inbound.
2. Bridge applied the DM sender allowlist to group participants, so any
   non-owner member of an allowlisted support group was dropped before
   Python.
3. Gateway authz treated WHATSAPP_GROUP_ALLOWED_USERS as a sender list
   (or ignored it), so even adapter-accepted group traffic hit
   Unauthorized user for members not also on the DM allowlist.

Also forwards owner-typed (fromMe) group messages when
WHATSAPP_FORWARD_OWNER_MESSAGES is on (personal-number bot) or when
mode is self-chat, so operators can talk to the agent in groups.

Default OFF / empty-config deny-all semantics preserved. Explicit
allow_from: [] does not widen via a stale env allowlist.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins platform/whatsapp WhatsApp Business adapter area/auth Authentication, OAuth, credential pools sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jul 21, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for tracing the full intake path. Current main still has the three claimed failure points: plugins/platforms/whatsapp/adapter.py:411-413 reads allowlists only from config.extra; scripts/whatsapp-bridge/bridge.js:644 applies the DM sender list to group participants; and gateway/authz_mixin.py:425-438 / :501-504 omit WhatsApp from chat-scoped group authorization.

Problems

  • The PR's documentation checklist says this is already documented, but it is not. website/docs/reference/environment-variables.md:356-362 lists only WHATSAPP_ALLOWED_USERS and WHATSAPP_ALLOW_ALL_USERS; its group entries at :376-379 are Cloud-adapter-specific. This change makes Baileys group policy and JID allowlists a supported user-facing configuration path.

Suggested changes

  • Document the Baileys group-policy variables and a group-JID example in the environment-variable reference and WhatsApp guide. Explicitly distinguish the group chat allowlist from the DM sender allowlist.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 30, 2026
@eduardo

eduardo commented Jul 30, 2026

Copy link
Copy Markdown

Just adding this comment for maintainers comparing this with #73465, which we opened:

The current Node DM sender check is not suitable for group messages because it checks the individual participant's phone number. In an allowed group, that can reject every member who is not also on the private DM allowlist.

Both PRs fix that problem, but in different ways. This PR lets group messages past the Node DM sender check and relies on the Python group policy downstream. In #73465, we replace the incorrect DM check with a group-specific check in Node using WHATSAPP_GROUP_POLICY and the group JID allowlist, then keep the existing Python checks as a second layer.

This PR also changes adapter environment loading, gateway authorization, and fromMe group handling. Those are separate from the focused bridge fix in #73465.

Posting this so maintainers can evaluate the overlapping fix and the additional changes separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P2 Medium — degraded but workaround exists platform/whatsapp WhatsApp Business adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants