Skip to content

security(slack): isolate room slash auth from DM pairing-store entries#26052

Closed
bmendonca3 wants to merge 2 commits intoopenclaw:mainfrom
bmendonca3:bm/security-6th-20260225
Closed

security(slack): isolate room slash auth from DM pairing-store entries#26052
bmendonca3 wants to merge 2 commits intoopenclaw:mainfrom
bmendonca3:bm/security-6th-20260225

Conversation

@bmendonca3
Copy link
Copy Markdown
Contributor

@bmendonca3 bmendonca3 commented Feb 25, 2026

Summary

Slack slash command authorization in room contexts currently mixes two trust scopes:

  • explicit owner/channel authorization (channels.slack.allowFrom, channels.slack.channels.<id>.users)
  • DM pairing-store state (readChannelAllowFromStore("slack"))

That allows a sender who is only present in DM pairing-store state to be treated as owner-authorized for channel slash commands.

This PR keeps DM pairing-store entries scoped to DM authorization only, and keeps room/channel slash authorization bound to explicit room/owner config.

Change Type

  • Security fix
  • Regression test

Scope

  • src/slack/monitor/slash.ts
  • src/slack/monitor/slash.test.ts

Security Impact

High (AuthZ boundary bypass on privileged command surface).

Before this patch, a DM-paired user could execute Slack slash commands in channel/group contexts without being in the explicit owner allowlist for room command authorization.

Worst case: unauthorized user can trigger high-privilege native slash commands in shared channels where only explicit owner/channel users should be authorized.

Repro + Verification

Deterministic repro (local):

  1. Checkout parent commit (git checkout 6cde6a641dd20a1b65687218b66000a98795bf98^).
  2. Run:
    • pnpm exec vitest run src/slack/monitor/slash.test.ts --maxWorkers=1
  3. Observe failure for:
    • blocks channel slash commands for senders authorized only via DM pairing store
    • pre-fix behavior dispatches command with CommandAuthorized: true.

Post-fix verification:

  • pnpm exec vitest run src/slack/monitor/slash.test.ts --maxWorkers=1
  • all tests pass.

Evidence

Dedupe checks:

Code-level evidence:

  • Room/channel owner authorization now uses static ctx.allowFrom only.
  • DM checks continue using effective DM allowlist (allowFrom + pairing-store) to preserve DM pairing behavior.
  • Added failing-before/passing-after regression test proving the bypass.

Human Verification

  1. Configure Slack with:
    • commands.useAccessGroups: true
    • channels.slack.allowFrom: ["U_OWNER"]
  2. Ensure attacker user (U_ATTACKER) exists only in Slack pairing store (not in static allowFrom).
  3. In a Slack channel, run slash command as U_ATTACKER.
  4. Expected after fix: ephemeral unauthorized response and no dispatch.

Compatibility / Migration

No schema/config migration.

Behavioral change: room/channel slash authorization no longer treats DM pairing-store entries as owner authorization. Operators must use explicit channels.slack.allowFrom and/or per-channel users allowlists for room authorization.

Failure Recovery

If rollback is required, revert this commit to restore prior behavior. The regression test can be kept to document expected secure behavior and prevent accidental reintroduction.

Risks and Mitigations

Risk:

  • Deployments that implicitly relied on DM pairing-store entries for room/channel slash authorization will now receive unauthorized responses.

Mitigation:

  • Add intended room command senders to channels.slack.allowFrom and/or channels.slack.channels.<id>.users explicitly.

Greptile Summary

This PR fixes a critical authorization boundary bypass in Slack slash command handling. Before this fix, users who were only authorized via DM pairing store could execute slash commands in channel/group contexts where only explicitly configured owner/channel users should be authorized.

The fix introduces a new variable ownerAllowFromLower that is conditionally set based on context:

  • For room/channel contexts (isRoomish): uses only static ctx.allowFrom configuration
  • For DM contexts: uses effectiveAllowFromLower which includes both static config and pairing store entries

This ensures DM pairing-store entries remain scoped to DM authorization only, while room/channel slash authorization is bound exclusively to explicit owner/channel configuration.

The regression test validates the fix by mocking a pairing store entry for U_ATTACKER while setting static allowFrom to U_OWNER, then verifying that U_ATTACKER receives an unauthorized response when attempting to use slash commands in a channel context.

Confidence Score: 5/5

  • This PR is safe to merge - it fixes a high-severity authorization bypass without introducing new risks
  • The fix is surgical and well-targeted: it introduces a single conditional variable assignment that separates DM pairing authorization from room/channel authorization. The change preserves existing DM behavior (still uses pairing store) while correctly restricting room contexts to static configuration only. The regression test proves the fix works and prevents reintroduction of the vulnerability.
  • No files require special attention - both implementation and test changes are straightforward

Last reviewed commit: 6cde6a6

@Takhoffman Takhoffman added the close:superseded PR close reason label Mar 1, 2026
@Takhoffman
Copy link
Copy Markdown
Contributor

Thanks for the contribution and the security focus here.

Closing this as superseded because the relevant auth-boundary hardening has already landed on main through newer changes, and merging this branch now would add duplicate or stale behavior.

If you want, we can open a fresh, narrowly-scoped follow-up PR on top of current main for any remaining gap.

@Takhoffman Takhoffman closed this Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack close:superseded PR close reason size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants