Skip to content

security(discord): scope DM component pairing auth to accountId#26671

Closed
bmendonca3 wants to merge 2 commits intoopenclaw:mainfrom
bmendonca3:bm/discord-pairing-account-scope-20260225-r19
Closed

security(discord): scope DM component pairing auth to accountId#26671
bmendonca3 wants to merge 2 commits intoopenclaw:mainfrom
bmendonca3:bm/discord-pairing-account-scope-20260225-r19

Conversation

@bmendonca3
Copy link
Copy Markdown
Contributor

@bmendonca3 bmendonca3 commented Feb 25, 2026

Summary

Discord DM component authorization (agent-components) used channel-level pairing-store reads/writes without accountId. In multi-account setups, this can let pairing approvals from one Discord account influence DM component authorization in another account.

This PR scopes the DM component pairing-store read/write calls to the active Discord account.

Change Type

  • Security fix (authz boundary hardening)
  • Tests

Scope

  • src/discord/monitor/agent-components.ts
  • src/discord/monitor/monitor.test.ts

Security Impact

  • Boundary crossed (before fix): account-level DM component auth read/wrote unscoped pairing-store data.
  • Practical impact: paired sender state from account A could authorize DM component interactions against account B.
  • Worst case: cross-account execution of component-triggered agent actions in shared gateways running multiple Discord accounts.

Repro + Verification

Deterministic repro (local)

  1. Configure two Discord accounts in one gateway (accountA, accountB) with DM policy pairing.
  2. Trigger an unauthorized DM component interaction in accountA; pair and approve that sender.
  3. Trigger the same sender against accountB.
  4. Before fix: component auth path can consume/write unscoped pairing-store data.
  5. After fix: component auth path scopes read/write to the active accountId.

Automated verification

pnpm vitest run --config vitest.unit.config.ts --maxWorkers=1 src/discord/monitor/monitor.test.ts

Passes with assertions that the DM component auth path calls:

  • readChannelAllowFromStore("discord", process.env, accountId)
  • upsertChannelPairingRequest({ ..., accountId })

Evidence

Human Verification

  • Confirmed ensureDmComponentAuthorized now passes ctx.accountId into both pairing-store read and pairing request upsert.
  • Added regression assertions in monitor.test.ts for account-scoped call arguments.

Compatibility / Migration

  • No config migration required.
  • Existing behavior remains unchanged for single-account Discord setups.

Failure Recovery

  • Revert this PR commit to restore prior behavior.
  • If needed operationally, temporarily set Discord DM policy to open while reconciling account-specific pairing approvals.

Risks and Mitigations

  • Risk: users may need separate pairing approvals per account (intended by boundary).
  • Mitigation: regression coverage now asserts account-scoped reads/writes in DM component auth path.

Greptile Summary

This PR fixes a cross-account authorization boundary issue in Discord DM component interactions. The fix correctly scopes pairing-store reads and pairing request creation to accountId in ensureDmComponentAuthorized.

Key changes:

  • readChannelAllowFromStore now receives ctx.accountId parameter
  • upsertChannelPairingRequest now includes accountId field
  • Test coverage added to verify account-scoped calls

Security impact:
The fix addresses the stated vulnerability where pairing approvals from one Discord account could authorize component interactions in another account within multi-account gateway setups. The implementation is correct and test coverage validates the account-scoped behavior.

Scope note:
This PR specifically addresses DM component authorization (agent-components.ts). Similar unscoped readChannelAllowFromStore and upsertChannelPairingRequest calls exist in:

  • src/discord/monitor/native-command.ts (lines 1364, 1384-1391)
  • src/discord/monitor/message-handler.preflight.ts (lines 183, 202-209)

These files handle DM message/command authorization and may have the same cross-account pairing state issue, but are outside this PR's scope. The PR description correctly limits scope to "DM component" auth.

Confidence Score: 4/5

  • This PR is safe to merge with minimal risk - it correctly fixes the stated DM component authorization boundary issue
  • Score reflects correct implementation of the security fix with proper test coverage. The fix is narrowly scoped to DM component authorization and properly passes accountId to pairing functions. Tests verify the account-scoped behavior. Score is 4 (not 5) because similar unscoped pairing calls exist in related Discord DM authorization paths (native-command.ts, message-handler.preflight.ts), suggesting this may be a partial fix of a broader pattern - however, the PR description correctly scopes this to "DM component" auth specifically.
  • No files in this PR require special attention - the implementation is clean and test coverage validates the fix

Last reviewed commit: 4ed219f

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Copy Markdown
Contributor Author

@bmendonca3 bmendonca3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Submitting pending review to unblock thread replies.

@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: S size: XS and removed size: XS agents Agent runtime and tooling size: S labels Feb 27, 2026
@thewilloftheshadow
Copy link
Copy Markdown
Member

Superceded by existing commits on main

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

Labels

channel: discord Channel integration: discord size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants