Skip to content

WhatsApp plugin silently ignores route bindings (security-relevant) #75211

Description

@juanez2024

Bug: WhatsApp plugin silently ignores bindings route configuration

Version: OpenClaw 2026.4.14
Plugin: whatsapp
Severity: Security-relevant — silently routes ALL WA inbound to default agent regardless of configured bindings

Summary

The WhatsApp plugin does not implement compileConfiguredBinding / matchInboundConversation (the API contract that other channel plugins like bluebubbles, feishu, imessage, line use to honor bindings[] in openclaw.json).

As a result, declaring routing rules like:

{
  "bindings": [
    {
      "type": "route",
      "agentId": "relay",
      "match": { "channel": "whatsapp", "accountId": "+51XXXXXXXXX" }
    }
  ]
}

…is silently ignored for the WhatsApp channel. All WA inbound messages fall through to the default agent (first entry in agents.list if none is marked default: true).

Why this matters (security)

In our deployment, the default agent (main) has full tool access (exec, subagents, read, write, image, web). The relay agent is restricted to exec only and is meant for team contacts.

We assumed bindings were enforced. They are not. We discovered 9 active sessions in our main agent for team WA numbers, when those should have been routed to relay. This effectively means any team contact had a path to a fully-privileged agent.

There is no warning, no log line, no error — the binding rules are just decorative for WA.

Reproduction

  1. Use openclaw 2026.4.14 with WhatsApp plugin enabled
  2. Configure agents.list with main and relay
  3. Add to bindings:
    { "type": "route", "agentId": "relay", "match": { "channel": "whatsapp", "accountId": "+51XXXXXXXXX" } }
  4. Send a WA message from +51XXXXXXXXX to the bot
  5. Observe: session created at agents/main/sessions/sessions.json under key agent:main:whatsapp:direct:+51XXXXXXXXX — NOT in relay

Confirmation in source

In dist/extensions/<plugin>/api.js (or equivalent):

$ grep -l "compileConfiguredBinding" dist/extensions/*/api.js
dist/extensions/bluebubbles/api.js
dist/extensions/feishu/api.js
dist/extensions/imessage/api.js
dist/extensions/line/api.js
# ← whatsapp is missing

The WhatsApp plugin under dist/extensions/whatsapp/ (1146 files, including channel-plugin-api.js, api.js) does not export compileConfiguredBinding nor matchInboundConversation.

binding-registry-CUcd4-sZ.js requires both for resolveConfiguredBindingProvider to return non-null:

if (!plugin || !provider || !provider.compileConfiguredBinding || !provider.matchInboundConversation) return null;

For WA plugin this returns null → binding rule is dropped silently.

Expected behavior

WA plugin should implement these two functions consistently with other channel plugins, OR emit a log warning when bindings[].match.channel === "whatsapp" is found but unsupported, so operators don't assume security policies are in effect.

Workaround we deployed

Defense-in-depth across 4 layers:

  1. Purge agent:main:whatsapp:direct:+57X sessions for team numbers (cron */5)
  2. Hard rule in main agent's BOOT.md: do not call any privileged tool if sender_id is not the owner
  3. Caller-allowlist guard at the top of sensitive scripts (odoo_query.py etc.) — reads latest user message metadata for sender_id, exits 99 if not in allowlist
  4. Custom watchdog (wa_relay_watchdog.sh) that detects unforwarded inbound and auto-restarts relay

Workarounds work but rely on careful coordination. Native binding support in the WA plugin would let us delete most of this.

Environment

  • OpenClaw 2026.4.14 (commit 323493f)
  • Node 20.x in Docker container
  • WhatsApp plugin via Baileys
  • Linux (Ubuntu 22.04 ARM64 host)

Happy to provide more details or test a fix. Thanks for OpenClaw — it's been great otherwise.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.securitySecurity documentationstaleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions