Skip to content

fix(security): prevent cross-channel reply routing in shared sessions#24571

Merged
steipete merged 3 commits into
openclaw:mainfrom
brandonwise:fix/cross-channel-reply-routing
Feb 25, 2026
Merged

fix(security): prevent cross-channel reply routing in shared sessions#24571
steipete merged 3 commits into
openclaw:mainfrom
brandonwise:fix/cross-channel-reply-routing

Conversation

@brandonwise

@brandonwise brandonwise commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #24152 — cross-channel reply routing privacy leak in shared sessions.

Problem

When dmScope="main" (the default), all DM channels share a single session. The session's lastChannel/lastTo fields get overwritten by each inbound message, regardless of source channel.

Race condition: If a Slack DM arrives while the agent is generating a WhatsApp reply, lastChannel flips to "slack" and the reply routes to the Slack sender instead of the WhatsApp user — a privacy violation.

Reproduction conditions (from issue):

  • Active WhatsApp conversation in progress
  • Incoming Slack system message (team member DM)
  • Agent generates response → delivered to Slack DM instead of WhatsApp

Fix

Adds optional turnSourceChannel, turnSourceTo, turnSourceAccountId, and turnSourceThreadId parameters to:

  1. resolveSessionDeliveryTarget() in targets.ts
  2. resolveAgentDeliveryPlan() in agent-delivery.ts

When turnSourceChannel is set, it overrides the session-level lastChannel for "last" channel resolution. This ensures the reply always routes back to the channel that originated the turn, regardless of concurrent inbound messages from other channels.

Key design decisions:

  • Backward compatible — all new parameters are optional; existing call sites work unchanged
  • Opt-in — callers pass the originating channel context when they want cross-channel safety
  • No session schema changes — operates at the delivery resolution layer, not storage
  • Follows existing patterns — mirrors the requestedChannel / explicitTo parameter style

Changes

File Change
src/infra/outbound/targets.ts Add turnSource* params to resolveSessionDeliveryTarget()
src/infra/outbound/agent-delivery.ts Add turnSource* params to resolveAgentDeliveryPlan(), pass through to target resolution
src/infra/outbound/targets.test.ts 4 new test cases for cross-channel guard

Test cases

  1. turnSourceChannel overrides session lastChannel when provided
  2. ✅ Falls back to session lastChannel when turnSourceChannel is absent
  3. ✅ Explicit requestedChannel takes priority over turnSourceChannel
  4. ✅ Preserves turnSourceAccountId and turnSourceThreadId

Next steps

Upstream callers (channel monitors, agent turn pipeline) need to pass turnSourceChannel when initiating turns. This PR provides the infrastructure; wiring the callers is a follow-up.


AI-assisted: Claude analyzed the routing code and authored the fix. Human reviewed the approach and design decisions.

Greptile Summary

Adds optional turnSource* parameters to delivery resolution functions to prevent cross-channel reply routing in shared sessions (dmScope="main"). When a turn originates from WhatsApp but a concurrent Slack message updates the session's lastChannel, replies could be misrouted to Slack—this fix ensures replies route back to the originating channel by letting callers override session state with turn-specific context.

Key changes:

  • resolveSessionDeliveryTarget() and resolveAgentDeliveryPlan() accept new optional turnSourceChannel, turnSourceTo, turnSourceAccountId, and turnSourceThreadId parameters
  • When turnSourceChannel is set, it overrides session-level lastChannel for "last" channel resolution
  • Backward compatible—all parameters optional, existing call sites unchanged
  • Test coverage includes cross-channel guard scenarios and priority handling

As noted in PR description: This provides the infrastructure; upstream callers (channel monitors, agent turn pipeline) need updates in follow-up work to pass turn source context.

Confidence Score: 5/5

  • Safe to merge with minimal risk—addresses privacy issue with backward-compatible infrastructure
  • Clean implementation following existing patterns, comprehensive test coverage for new functionality, well-documented with issue references, backward compatible design, and PR explicitly scopes this as infrastructure-only (follow-up needed for caller integration)
  • No files require special attention

Last reviewed commit: 53250c8

@steipete
steipete merged commit 389ccda into openclaw:main Feb 25, 2026
25 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed via temp rebase onto main.

  • Gate: pnpm check && pnpm build && pnpm test && pnpm check:docs (full test run hit unrelated flaky src/gateway/server.auth.test timeout assertion); pnpm test src/infra/outbound/targets.test.ts src/infra/outbound/agent-delivery.test.ts src/commands/agent.delivery.test.ts src/gateway/server-methods/agent.test.ts
  • Land commit: 93dc388
  • Merge commit: 389ccda

Thanks @brandonwise!

margulans pushed a commit to margulans/Neiron-AI-assistant that referenced this pull request Feb 25, 2026
Jackson3195 pushed a commit to Jackson3195/openclaw-with-a-personal-touch that referenced this pull request Feb 25, 2026
kevinWangSheng pushed a commit to kevinWangSheng/openclaw that referenced this pull request Feb 26, 2026
kevinWangSheng pushed a commit to kevinWangSheng/openclaw that referenced this pull request Feb 26, 2026
oskarfreye pushed a commit to oskarfreye/openclaw that referenced this pull request Feb 27, 2026
hughdidit pushed a commit to hughdidit/DAISy-Agency that referenced this pull request Mar 1, 2026
…@brandonwise)

(cherry picked from commit 885452f)

# Conflicts:
#	src/infra/outbound/agent-delivery.ts
#	src/infra/outbound/targets.test.ts
#	src/infra/outbound/targets.ts
hughdidit pushed a commit to hughdidit/DAISy-Agency that referenced this pull request Mar 3, 2026
…@brandonwise)

(cherry picked from commit 885452f)

# Conflicts:
#	src/infra/outbound/agent-delivery.ts
#	src/infra/outbound/targets.test.ts
#	src/infra/outbound/targets.ts
GixGosu pushed a commit to GixGosu/openclaw that referenced this pull request Mar 4, 2026
…rce routing

This fixes group message routing failures introduced in v2026.2.24 when
PR openclaw#24571 added fail-closed security hardening for shared-session
cross-channel replies.

The issue: `buildEmbeddedContextFromTemplate` was only setting
`messageProvider` but not `messageChannel`. The delivery planner's
`turnSourceChannel` logic reads from `runContext.messageChannel`, so
without it set, the turn-source binding fails and replies to group
messages don't route back to the originating channel.

This affects all plugin-based channels (Mattermost, etc.) and potentially
built-in channels (Telegram, WhatsApp) in group/channel contexts where
the session might be shared across channels.

The fix adds `messageChannel` alongside `messageProvider` using the same
resolved value from `resolveOriginMessageProvider`.

Related issues:
- openclaw#24571 (original security hardening PR)
- openclaw#29637 (Telegram group messages not working)
- openclaw#19509 (WhatsApp group messages not working)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
GixGosu pushed a commit to GixGosu/openclaw that referenced this pull request Mar 4, 2026
…tibility

The change in v2026.2.24 that made pairing store DM-only broke existing
setups where users relied on DM pairing to access group chats. This restores
the previous behavior where storeAllowFrom is included in effectiveGroupAllowFrom.

Added groupAuthIncludesPairingStore option (defaults to true) for users who
want to opt into the stricter v2026.2.24 behavior.

Note: Command authorization in groups still requires explicit allowlist
(not pairing store) to maintain security separation.

See: openclaw#24571

Co-Authored-By: Claude Opus 4.5 <[email protected]>
thebenjaminlee pushed a commit to escape-velocity-ventures/openclaw that referenced this pull request Mar 7, 2026
john-ver pushed a commit to apmcoin/apmclaw that referenced this pull request Mar 9, 2026
dustin-olenslager pushed a commit to dustin-olenslager/ironclaw-supreme that referenced this pull request Mar 24, 2026
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Security / Privacy / Session Routing

2 participants