Skip to content

[FEATURE]: Narrow RBAC Layer 2 permission checks to match session-token team scope #3799

@crivetimihai

Description

@crivetimihai

Context

PR #3217 adds session-token team narrowing at Layer 1 (visibility / token scoping). When a session token carries a JWT teams claim, resolve_session_teams() narrows the visible scope to the intersection of DB teams and JWT teams.

However, Layer 2 (RBAC / permission checks) is not narrowed to match. When team_id cannot be derived from the request context, PermissionService.check_permission() is called with check_any_team=True, which aggregates permissions from all of the user's team-scoped roles — not just the ones matching the narrowed token_teams.

Problem

A session token narrowed to team A for visibility can still satisfy RBAC checks using roles the user holds in team B.

Example:

  • User has developer role in team A (tools.read, tools.execute)
  • User has team_admin role in team B (teams.*, tools.create, etc.)
  • User creates a session narrowed to team A via JWT teams: ["A"]
  • Layer 1: correctly scoped to team A resources only
  • Layer 2: check_any_team=True aggregates roles from both A and B
  • Result: user gains teams.* permissions from team B despite narrowing to team A

Affected Code

  • mcpgateway/middleware/rbac.py:563 — sets check_any_team=True for session tokens without team_id
  • mcpgateway/services/permission_service.py:134get_user_permissions(..., include_all_teams=check_any_team) does not filter by token_teams
  • mcpgateway/services/permission_service.py:483 — includes ALL team-scoped roles when include_all_teams=True

Proposed Fix

When check_any_team=True and token_teams is a non-empty list (narrowed session), filter the team-scoped roles in get_user_permissions() to only include roles from teams in token_teams. This preserves existing behavior for un-narrowed sessions (where token_teams covers full DB membership) while correctly restricting narrowed sessions.

Note

This is a pre-existing behavior in the two-layer model, not introduced by #3217. The PR makes it more visible by advertising session-token narrowing that only applies to Layer 1. This issue tracks closing the gap in Layer 2.

Metadata

Metadata

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafeenhancementNew feature or requestsecurityImproves security

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions