Skip to content

[security] fix(permissions): scope channel approval targets#2566

Merged
gavrielc merged 1 commit into
nanocoai:mainfrom
Hinotoi-agent:fix/channel-approval-target-authz
May 22, 2026
Merged

[security] fix(permissions): scope channel approval targets#2566
gavrielc merged 1 commit into
nanocoai:mainfrom
Hinotoi-agent:fix/channel-approval-target-authz

Conversation

@Hinotoi-agent

Copy link
Copy Markdown
Contributor

Summary

This PR tightens the channel-registration approval flow so scoped admins can only connect unknown channels to agent groups they are authorized to administer.

Before this change, the pending channel approval row used one agent group as the approval context, but the follow-up selection and final connect:<agentGroupId> response could point at a different target agent group. A scoped admin for the approval context could therefore attempt to register the unknown channel against an out-of-scope target group.

This patch fixes both sides of the boundary:

  • the approval cards only show target agent groups visible to the actual approver
  • the response handler re-checks target-group authorization before applying a pending channel registration
  • regression coverage verifies that a scoped admin cannot connect a channel to another group by selecting or submitting an out-of-scope target

Security issues covered

This PR covers one authorization issue:

Issue Boundary Fix
Scoped admin channel registration target authorization A scoped admin may approve a channel registration for one group but must not be able to attach that channel to an unrelated group Filter target options by approver scope and enforce target authorization at apply time

Before this PR

  • The approval flow selected an approver based on a reference agent group.
  • The initial and follow-up approval cards were built from all agent groups.
  • The final connect:<agentGroupId> response checked that the clicker could approve the pending row, but did not also verify that the same clicker could administer the selected target group.
  • A stale, hidden, or tampered response value could still reference an out-of-scope target group.

After this PR

  • Approval options are filtered through the approver identity.
  • Agent-selection follow-up cards only include groups where the approver has admin privilege.
  • The response handler rejects connect:<agentGroupId> if the approver is not authorized for that target group.
  • Unauthorized target attempts leave the pending approval in place and do not create channel-to-agent-group wiring.

Why this matters

Channel registration controls which external messaging channels can send into an agent group. Scoped admins are intentionally limited to the groups they administer. If the approval context and selected target group diverge, a scoped admin can cross that boundary and wire a channel into a group they should not control.

That can expose an out-of-scope agent group to messages from an unapproved channel and let a scoped administrator influence or observe behavior outside their delegated administrative scope.

Attack flow

  1. A scoped admin has admin rights for agent group A, but not agent group B.
  2. An unknown messaging channel triggers the channel-registration approval flow using group A as the approval context.
  3. The scoped admin receives the approval card.
  4. The approval follow-up or callback value submits connect:B.
  5. On vulnerable code, the handler accepts the target and creates the channel wiring for group B.
  6. After this PR, B is not exposed in selectable options for that approver, and a forged or stale connect:B value is rejected before any wiring is created.

Affected code

  • src/modules/permissions/channel-approval.ts
    • builds initial approval options
    • builds agent-selection follow-up options
  • src/modules/permissions/index.ts
    • handles pending channel approval responses
    • applies connect:<agentGroupId> target selection
  • src/modules/permissions/channel-approval.test.ts
    • regression coverage for scoped-admin cross-group channel registration

Root cause

  • The pending approval authorization and target authorization were treated as the same decision.
  • The approval row stored the reference group used to choose an approver, but a later response could select a different target group.
  • Option generation did not take the approver identity into account.
  • The final apply step did not re-check admin privilege for the selected target agent group.

CVSS assessment

Issue: scoped admin channel registration target authorization bypass

CVSS v3.1: 6.4 Medium

Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N

Rationale:

  • Network-accessible channel approval callbacks can carry the selected target value.
  • The attacker needs a scoped admin role for at least one group, so privileges are required.
  • No victim user interaction is required beyond the attacker operating their own scoped-admin approval.
  • Scope changes because a scoped admin can affect an agent group outside their delegated scope.
  • Impact is bounded to channel registration/wiring, with potential confidentiality and integrity impact for the out-of-scope group.

Safe reproduction steps

A safe local reproduction is included in the regression test:

  1. Create two agent groups, ag-1 and ag-2.
  2. Grant telegram:scoped-admin admin rights only for ag-1.
  3. Trigger an unknown-channel registration flow.
  4. Handle the approval as telegram:scoped-admin.
  5. Verify the follow-up options include connect:ag-1 but not connect:ag-2.
  6. Submit a forged/stale connect:ag-2 response value.
  7. Verify no messaging_group_agents row is created and the pending approval remains pending.

Expected vulnerable behavior

On vulnerable code, the final connect:ag-2 response can be accepted even though the approver only administers ag-1. That creates messaging-channel wiring for an out-of-scope target group.

Changes in this PR

  • Adds approver-aware filtering for channel approval option generation.
  • Passes the actual approval delivery user into the initial card builder.
  • Passes the approver ID into the agent-selection follow-up builder.
  • Adds an apply-time authorization check before accepting connect:<targetAgentGroupId>.
  • Adds regression coverage for the scoped-admin cross-group target case.

Files changed

File What changed
src/modules/permissions/channel-approval.ts Filters initial and follow-up target options by hasAdminPrivilege(approverUserId, agentGroup.id)
src/modules/permissions/index.ts Passes approver identity into option generation and rejects unauthorized target groups at apply time
src/modules/permissions/channel-approval.test.ts Adds scoped-admin regression coverage for out-of-scope target filtering and forged target rejection

Maintainer impact

This is intended to be a narrow authorization fix. It does not change the owner/global-admin flow, the pending approval schema, or the general unknown-channel registration behavior. It only scopes target selection to the approver's existing authorization and rejects target values that do not match that scope.

Fix rationale

The approval flow has two separate security decisions:

  1. whether the clicker is allowed to respond to the pending approval; and
  2. whether the selected target agent group is within that clicker's administrative scope.

Both checks need to be enforced. Filtering options improves the normal UI path, while the response-handler check protects the server-side boundary against stale cards, hidden options, or direct callback/value submission.

Type of change

  • Security fix
  • Regression test
  • New feature
  • Breaking change
  • Documentation-only change

Test plan

Commands run locally:

pnpm vitest run src/modules/permissions/channel-approval.test.ts -t 'scoped admin'
pnpm vitest run src/modules/permissions/channel-approval.test.ts
pnpm format:check
pnpm typecheck
pnpm exec eslint src/modules/permissions/channel-approval.ts src/modules/permissions/index.ts src/modules/permissions/channel-approval.test.ts
pnpm test
git diff --check

Final validation passed after formatting the touched files. The focused channel-approval test file passed, and the full test suite passed locally.

Disclosure notes

This PR is intentionally bounded to the scoped-admin channel-registration target authorization path. It does not claim a broader bypass of all approval flows or all permission checks. The fix is submitted directly as a defensive code change with regression coverage.

Filter channel registration target options to the approver's authorized agent groups and re-check target authorization before applying a pending approval. Add regression coverage for scoped admins attempting to connect channels to out-of-scope groups.
@gavrielc gavrielc merged commit 0eef8fa into nanocoai:main May 22, 2026
2 checks passed
@gavrielc

Copy link
Copy Markdown
Collaborator

@Hinotoi-agent Thank you for the contribution!!

tamasPetki pushed a commit to tamasPetki/nanoclaw that referenced this pull request Jun 4, 2026
…val-target-authz

[security] fix(permissions): scope channel approval targets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants