Confidence Note
This report is based on source analysis of version 1.0.4 and I have not yet dynamically validated it against a live instance.
Summary
get_current_user_with_permissions() propagates token_teams into the authenticated user context, and other sensitive admin endpoints explicitly reject narrowed admin sessions when token_teams is not None. However, the OAuth DCR management endpoints only call _require_admin_user(), which checks is_admin but ignores token_teams.
As a result, a scoped admin token appears able to list, retrieve, and delete global RegisteredOAuthClient records outside its allowed team scope.
Impact
If this behavior is reachable in deployment, an administrative token that is intentionally narrowed to specific teams may still access the global OAuth dynamic client registration management surface. That would allow cross-scope visibility into registered clients and may also allow deletion of client registrations outside the token's intended authorization boundary.
Affected Endpoints
GET /registered-clients
GET /registered-clients/{gateway_id}
DELETE /registered-clients/{client_id}
Technical Details
The RBAC layer includes token_teams in the authenticated user context:
mcpgateway/middleware/rbac.py:443-455
The helper used by the OAuth DCR management endpoints only verifies is_admin:
mcpgateway/routers/oauth_router.py:192-203
The affected endpoints rely on that helper and do not reject narrowed admin sessions:
mcpgateway/routers/oauth_router.py:988-1033
mcpgateway/routers/oauth_router.py:1040-1084
mcpgateway/routers/oauth_router.py:1093-1136
By contrast, another sensitive admin surface explicitly blocks narrowed tokens by checking whether token_teams is not None:
mcpgateway/routers/tokens.py:624-633
The registered OAuth client objects appear to be stored globally and are queried directly without team scoping in these endpoints:
mcpgateway/db.py:5317-5335
This combination suggests that a scoped admin session may enumerate or delete registered OAuth clients beyond its intended scope.
Reproduction Idea
Based on source analysis, the likely reproduction path is:
- Obtain an authenticated admin token or session that is intentionally narrowed through
token_teams.
- Call
GET /registered-clients.
- Observe whether the response includes globally registered OAuth clients outside the teams allowed by the token.
- Call
GET /registered-clients/{gateway_id} for a gateway outside the narrowed scope.
- Attempt
DELETE /registered-clients/{client_id} against a registration outside the token's allowed team scope.
- If successful, this confirms cross-scope authorization bypass.
Root Cause
The authorization model distinguishes between full admin access and narrowed admin access, but the OAuth DCR management endpoints enforce only the admin bit and ignore the narrowing metadata carried in token_teams.
Suggested Remediation
- Apply the same un-narrowed admin check used in other sensitive endpoints to the OAuth DCR management endpoints.
- Enforce explicit scope validation before listing, retrieving, or deleting registered OAuth clients.
- Add tests covering narrowed admin tokens against all DCR management routes.
- Review other admin-only endpoints for similar
is_admin-only checks that ignore token_teams.
Code References
mcpgateway/middleware/rbac.py:443-455
mcpgateway/routers/oauth_router.py:192-203
mcpgateway/routers/oauth_router.py:988-1033
mcpgateway/routers/oauth_router.py:1040-1084
mcpgateway/routers/oauth_router.py:1093-1136
mcpgateway/routers/tokens.py:624-633
mcpgateway/db.py:5317-5335
Confidence Note
This report is based on source analysis of version
1.0.4and I have not yet dynamically validated it against a live instance.Summary
get_current_user_with_permissions()propagatestoken_teamsinto the authenticated user context, and other sensitive admin endpoints explicitly reject narrowed admin sessions whentoken_teams is not None. However, the OAuth DCR management endpoints only call_require_admin_user(), which checksis_adminbut ignorestoken_teams.As a result, a scoped admin token appears able to list, retrieve, and delete global
RegisteredOAuthClientrecords outside its allowed team scope.Impact
If this behavior is reachable in deployment, an administrative token that is intentionally narrowed to specific teams may still access the global OAuth dynamic client registration management surface. That would allow cross-scope visibility into registered clients and may also allow deletion of client registrations outside the token's intended authorization boundary.
Affected Endpoints
GET /registered-clientsGET /registered-clients/{gateway_id}DELETE /registered-clients/{client_id}Technical Details
The RBAC layer includes
token_teamsin the authenticated user context:mcpgateway/middleware/rbac.py:443-455The helper used by the OAuth DCR management endpoints only verifies
is_admin:mcpgateway/routers/oauth_router.py:192-203The affected endpoints rely on that helper and do not reject narrowed admin sessions:
mcpgateway/routers/oauth_router.py:988-1033mcpgateway/routers/oauth_router.py:1040-1084mcpgateway/routers/oauth_router.py:1093-1136By contrast, another sensitive admin surface explicitly blocks narrowed tokens by checking whether
token_teamsis notNone:mcpgateway/routers/tokens.py:624-633The registered OAuth client objects appear to be stored globally and are queried directly without team scoping in these endpoints:
mcpgateway/db.py:5317-5335This combination suggests that a scoped admin session may enumerate or delete registered OAuth clients beyond its intended scope.
Reproduction Idea
Based on source analysis, the likely reproduction path is:
token_teams.GET /registered-clients.GET /registered-clients/{gateway_id}for a gateway outside the narrowed scope.DELETE /registered-clients/{client_id}against a registration outside the token's allowed team scope.Root Cause
The authorization model distinguishes between full admin access and narrowed admin access, but the OAuth DCR management endpoints enforce only the admin bit and ignore the narrowing metadata carried in
token_teams.Suggested Remediation
is_admin-only checks that ignoretoken_teams.Code References
mcpgateway/middleware/rbac.py:443-455mcpgateway/routers/oauth_router.py:192-203mcpgateway/routers/oauth_router.py:988-1033mcpgateway/routers/oauth_router.py:1040-1084mcpgateway/routers/oauth_router.py:1093-1136mcpgateway/routers/tokens.py:624-633mcpgateway/db.py:5317-5335