Skip to content

security(allowlist): scope pairing-store operations to accountId#26693

Closed
bmendonca3 wants to merge 1 commit intoopenclaw:mainfrom
bmendonca3:bm/allowlist-store-account-scope-20260225
Closed

security(allowlist): scope pairing-store operations to accountId#26693
bmendonca3 wants to merge 1 commit intoopenclaw:mainfrom
bmendonca3:bm/allowlist-store-account-scope-20260225

Conversation

@bmendonca3
Copy link
Copy Markdown
Contributor

@bmendonca3 bmendonca3 commented Feb 25, 2026

Summary

  • Fixes an auth boundary miss in /allowlist where pairing-store reads/writes ignored account scope.
  • /allowlist list now reads pairing-store entries with the resolved accountId.
  • /allowlist add|remove now writes/removes pairing-store entries with the resolved accountId.
  • Adds regression coverage to prevent cross-account store bleed from command-path edits.

Change Type

  • Security fix
  • Regression tests

Scope

  • src/auto-reply/reply/commands-allowlist.ts
  • src/auto-reply/reply/commands.test.ts

Security Impact

  • Before this change, /allowlist store mutations were written unscoped, which could pollute shared pairing-store state across accounts.
  • In multi-account deployments, this could allow account-B edits to influence account-A DM authorization decisions through shared store state.
  • After this change, command-path store reads and mutations are account-scoped.

Repro + Verification

  1. Configure multi-account channel setup (same channel id, different account ids).
  2. From account B, execute /allowlist add dm --store <sender>.
  3. Observe pre-fix store mutation path used unscoped pairing-store state (missing accountId) and could affect other account evaluations.
  4. With this patch, store operations include resolved accountId and remain isolated per account.

Targeted tests:

  • pnpm exec vitest run src/auto-reply/reply/commands.test.ts --maxWorkers=1

Evidence

Human Verification

  • Run /allowlist list dm from different accounts and confirm paired store entries are account-specific.
  • Run /allowlist add dm --store <id> on account B and verify account A store output is unchanged.

Compatibility / Migration

  • Backward compatible.
  • No config schema changes.
  • Existing command UX unchanged; only store scoping behavior is corrected.

Failure Recovery

  • Revert this commit to restore prior behavior.
  • If needed, re-add entries with explicit account-scoped commands after rollback/reapply.

Risks and Mitigations

  • Risk: account-scoped behavior may surface previously hidden reliance on unscoped store edits.
  • Mitigation: regression tests assert scoped call contracts and command outputs remain stable.

Greptile Summary

This PR correctly scopes /allowlist command-path store mutations to accountId, preventing cross-account pollution when users manage allowlists via commands. The fix adds accountId parameters to readChannelAllowFromStore, addChannelAllowFromStoreEntry, and removeChannelAllowFromStoreEntry calls within the /allowlist command handler, and includes regression tests verifying account-scoped behavior.

However, the security boundary fix is incomplete. While command-path edits are now scoped, the actual runtime authorization checks in multiple channel handlers (Discord, Slack, Signal, iMessage, LINE) still call readChannelAllowFromStore without passing accountId. This means:

  • Account B can still execute /allowlist add dm --store <sender> to write scoped entries (fixed by this PR)
  • But when Account A receives a DM, the authorization check reads unscoped store state and will see entries from all accounts
  • Cross-account authorization bypass remains exploitable through the runtime evaluation path

The PR description claims "command-path store reads and mutations are account-scoped" but the command path is only used for management - the actual DM authorization decisions happen in channel-specific message handlers that were not updated.

Confidence Score: 1/5

  • Critical security issue - the authorization bypass vulnerability is only partially fixed
  • While the /allowlist command mutations are properly scoped, the runtime authorization checks in all channel handlers (Discord, Slack, Signal, iMessage, LINE) still read unscoped pairing-store state. This means the core vulnerability - cross-account authorization decisions - remains exploitable. The fix addresses symptom (command management) but not the disease (runtime evaluation).
  • All channel handler files that call readChannelAllowFromStore without accountId: src/discord/monitor/message-handler.preflight.ts, src/discord/monitor/native-command.ts, src/discord/monitor/agent-components.ts, src/slack/monitor/auth.ts, src/slack/monitor/slash.ts, src/signal/monitor/event-handler.ts, src/imessage/monitor/monitor-provider.ts, src/line/bot-handlers.ts, and src/security/audit-channel.ts

Last reviewed commit: 238f0ab

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

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Feb 25, 2026

Additional Comments (1)

src/auto-reply/reply/commands-allowlist.ts
While /allowlist command mutations are now scoped, the actual runtime authorization checks in channel handlers (Discord, Slack, Signal, iMessage, LINE) still call readChannelAllowFromStore without accountId, meaning they read unscoped store state and remain vulnerable to cross-account pollution.

Check src/discord/monitor/message-handler.preflight.ts:183, src/slack/monitor/auth.ts:7, src/signal/monitor/event-handler.ts:447, src/imessage/monitor/monitor-provider.ts:233, and src/line/bot-handlers.ts:119 - all missing accountId parameter.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/commands-allowlist.ts
Line: 119

Comment:
While `/allowlist` command mutations are now scoped, the actual runtime authorization checks in channel handlers (Discord, Slack, Signal, iMessage, LINE) still call `readChannelAllowFromStore` without `accountId`, meaning they read unscoped store state and remain vulnerable to cross-account pollution.

Check `src/discord/monitor/message-handler.preflight.ts:183`, `src/slack/monitor/auth.ts:7`, `src/signal/monitor/event-handler.ts:447`, `src/imessage/monitor/monitor-provider.ts:233`, and `src/line/bot-handlers.ts:119` - all missing accountId parameter.

How can I resolve this? If you propose a fix, please make it concise.

@bmendonca3
Copy link
Copy Markdown
Contributor Author

Addressed Greptile note:

Resolution is covered by channel-specific commits/PR branches:

@openclaw-barnacle
Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: S stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants