Skip to content

security(zalo): scope pairing approvals to accountId#26121

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

security(zalo): scope pairing approvals to accountId#26121
steipete merged 3 commits intoopenclaw:mainfrom
bmendonca3:bm/zalo-pairing-account-scope-20260225

Conversation

@bmendonca3
Copy link

@bmendonca3 bmendonca3 commented Feb 25, 2026

Summary

Zalo DM pairing authorization used channel-level pairing-store access without threading accountId, allowing pairing approvals from one Zalo account to influence DM authorization on another Zalo account in the same gateway runtime.

This patch scopes both pairing-store reads and pairing-request writes to the active account.

Change Type

  • Bug fix
  • Security hardening
  • Tests

Scope

  • extensions/zalo/src/monitor.ts
  • extensions/zalo/src/monitor.webhook.test.ts

Security Impact

Fixes an authz/session-isolation bypass in multi-account Zalo deployments:

  • Before: account A pairing state could authorize sender access for account B.
  • After: DM authorization and pairing requests are keyed by accountId, preventing cross-account approval bleed.

Repro + Verification

Deterministic repro (before fix)

  1. Configure two Zalo accounts (default and work) with dmPolicy=pairing.
  2. Approve/pair sender 123 on default.
  3. Send DM from sender 123 to work.
  4. Observe sender can be treated as allowlisted due to unscoped pairing-store read.

Post-fix behavior

  • Sender 123 is not implicitly allowlisted on work unless paired for work.

Regression test

  • Added webhook-level regression asserting DM pairing path calls:
    • readAllowFromStore("zalo", undefined, accountId)
    • upsertPairingRequest({ ..., accountId })

Test command

  • pnpm exec vitest run --config vitest.extensions.config.ts extensions/zalo/src/monitor.group-policy.test.ts extensions/zalo/src/monitor.webhook.test.ts --maxWorkers=1
  • Result: pass (13 passed).

Evidence

Dedupe search (no matching open/closed issue/PR found for this exact cross-account Zalo pairing scope bug):

Human Verification

  1. Run two Zalo accounts with separate trust boundaries.
  2. Pair sender on account A only.
  3. Send DM from same sender to account B.
  4. Confirm account B still requires independent pairing approval.

Compatibility / Migration

  • No schema/config migration required.
  • Behavior is stricter for multi-account setups: approvals are now account-scoped.

Failure Recovery

  • Revert this commit to restore old behavior.
  • If rollback is temporary, re-pair senders per account after reapplying the fix.

Risks and Mitigations

  • Risk: environments that relied on implicit cross-account approvals will see reduced access.
  • Mitigation: this aligns runtime behavior with expected account isolation; regression test locks scoped behavior.

Greptile Summary

Fixes a critical authorization bypass in multi-account Zalo deployments where pairing approvals from one account could authorize DM access on another account within the same gateway runtime.

The fix correctly scopes pairing operations to accountId by:

  • Passing account.accountId as the third parameter to readAllowFromStore("zalo", undefined, accountId) at extensions/zalo/src/monitor.ts:361
  • Adding accountId: account.accountId to the upsertPairingRequest call at extensions/zalo/src/monitor.ts:382

The regression test validates both operations are properly scoped and will prevent future regressions.

Confidence Score: 4/5

  • This security fix is safe to merge with one consideration for the zalouser extension
  • The fix correctly addresses the security vulnerability with proper scoping and test coverage. Score is 4 (not 5) because the sister extension zalouser appears to have the identical vulnerability pattern that should be addressed in a follow-up
  • No files in this PR require special attention, but consider reviewing extensions/zalouser/src/monitor.ts for the same vulnerability pattern

Last reviewed commit: 1a025d3

@bmendonca3
Copy link
Author

@greptileai please run security/code review on this PR.

@openclaw-barnacle openclaw-barnacle bot added channel: zalo Channel integration: zalo 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/zalo-pairing-account-scope-20260225 branch from fff821a to e4483dc Compare March 2, 2026 15:38
@steipete steipete merged commit 729ddfd 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/zalo/src/monitor.webhook.test.ts extensions/zalo/src/monitor.group-policy.test.ts
  • Land commit: e4483dc
  • Merge commit: 729ddfd

Thanks @bmendonca3!

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

Labels

channel: zalo Channel integration: zalo size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants