Skip to content

security(zalouser): scope pairing-store auth to accountId#26672

Merged
steipete merged 3 commits intoopenclaw:mainfrom
bmendonca3:bm/zalouser-pairing-account-scope-20260225
Mar 2, 2026
Merged

security(zalouser): scope pairing-store auth to accountId#26672
steipete merged 3 commits intoopenclaw:mainfrom
bmendonca3:bm/zalouser-pairing-account-scope-20260225

Conversation

@bmendonca3
Copy link

@bmendonca3 bmendonca3 commented Feb 25, 2026

Summary

  • Scope Zalouser DM pairing-store authorization reads to the active accountId.
  • Scope Zalouser pairing request writes to the active accountId.
  • Add regression coverage that reproduces cross-account DM authorization bleed from unscoped pairing-store lookups.

Change Type

  • Security fix
  • Tests

Scope

  • extensions/zalouser/src/monitor.ts
  • extensions/zalouser/src/monitor.account-scope.test.ts

Security Impact

  • Fixes an auth boundary bypass in multi-account Zalouser deployments.
  • Before: DM authorization used unscoped pairing-store reads and unscoped pairing request writes, so approvals from one account could influence another account.
  • After: both read and write paths are bound to the active Zalouser accountId.

Repro + Verification

  1. Configure two Zalouser accounts (alpha, beta) with dmPolicy: pairing and empty allowFrom.
  2. Ensure a sender is only present in unscoped/global pairing-store state (or approved under another account).
  3. Receive a DM from that sender on beta.
  4. Before fix: sender can be treated as allowlisted in beta by unscoped store access.
  5. After fix: sender is not allowlisted for beta; account-scoped pairing path is used.

Local verification run:

  • pnpm exec vitest run extensions/zalouser/src/monitor.account-scope.test.ts extensions/zalouser/src/channel.test.ts extensions/zalouser/src/send.test.ts --maxWorkers=1

Evidence

  • Code path with unscoped read/write before patch:
    • extensions/zalouser/src/monitor.ts
  • Account-scoped read/write after patch:
    • extensions/zalouser/src/monitor.ts
  • Regression test reproducing and enforcing account scoping:
    • extensions/zalouser/src/monitor.account-scope.test.ts
  • Dedupe searches for this exact issue showed no matching open/closed PRs or open issues:
    • gh search prs --repo openclaw/openclaw --match title,body -- "zalouser scope pairing approvals"
    • gh search prs --repo openclaw/openclaw --match title,body -- "zalouser pairing accountId"
    • gh search issues --repo openclaw/openclaw --match title,body -- "zalouser pairing accountId"

Human Verification

  • In a two-account Zalouser config, verify a sender approved/requested under one account cannot DM-authorize under another account.
  • Verify pairing reply is generated for the correct account when the sender is unauthorized in that account.

Compatibility / Migration

  • No schema changes.
  • Single-account behavior is unchanged.
  • Multi-account behavior is hardened to match account isolation expectations.

Failure Recovery

  • Revert this commit to restore previous behavior.
  • If operators relied on accidental cross-account sharing, re-approve senders explicitly per account.

Risks and Mitigations

  • Risk: stricter DM gating may surface where operators unintentionally depended on shared/global pairing-store behavior.
  • Mitigation: this is intentional security hardening for account isolation.

Greptile Summary

This PR fixes an auth boundary bypass in multi-account Zalouser deployments by scoping pairing-store reads and writes to the active accountId.

  • Scoped readAllowFromStore to use account.accountId (extensions/zalouser/src/monitor.ts:229)
  • Scoped upsertPairingRequest to include accountId: account.accountId (extensions/zalouser/src/monitor.ts:250)
  • Added comprehensive regression test that verifies account isolation (extensions/zalouser/src/monitor.account-scope.test.ts)

The fix follows the same pattern already used in WhatsApp (src/web/inbound/access-control.ts:66, :184) for multi-account scoping. Before this change, a sender approved in one account could bypass DM authorization checks in another account due to unscoped pairing-store lookups.

Confidence Score: 5/5

  • This PR is safe to merge with high confidence - it's a focused security fix with comprehensive test coverage
  • This is a well-executed security fix that: (1) addresses a real auth boundary bypass, (2) uses an established pattern from WhatsApp multi-account scoping, (3) includes regression tests that verify the fix, (4) has minimal surface area (only 2 changed call sites), and (5) is properly scoped to only the necessary changes
  • No files require special attention

Last reviewed commit: 6607511

@openclaw-barnacle openclaw-barnacle bot added channel: zalouser Channel integration: zalouser size: S experienced-contributor agents Agent runtime and tooling size: M and removed size: S agents Agent runtime and tooling size: M labels Feb 25, 2026
@steipete steipete force-pushed the bm/zalouser-pairing-account-scope-20260225 branch from 02b8596 to b55007b Compare March 2, 2026 15:34
@steipete steipete merged commit f1cab9c into openclaw:main Mar 2, 2026
9 checks passed
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Landed via temp rebase onto main.

  • Gate: pnpm test -- extensions/zalouser/src/monitor.account-scope.test.ts extensions/zalouser/src/channel.test.ts extensions/zalouser/src/send.test.ts
  • Land commit: b55007b
  • Merge commit: f1cab9c

Thanks @bmendonca3!

Linux2010 pushed a commit to Linux2010/openclaw that referenced this pull request Mar 2, 2026
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: zalouser Channel integration: zalouser size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants