Scoped admin OAuth DCR endpoints ignore token_teams restrictions and expose global registered clients
Medium6.4Published Aug 25, 2026
### 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 R...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| mcp-contextforge-gateway PyPI | < v1.0.7 | v1.0.7 |
Details and references
### 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: 1. Obtain an authenticated admin token or session that is intentionally narrowed through `token_teams`. 2. Call `GET /registered-clients`. 3. Observe whether the response includes globally registered OAuth clients outside the teams allowed by the token. 4. Call `GET /registered-clients/{gateway_id}` for a gateway outside the narrowed scope. 5. Attempt `DELETE /registered-clients/{client_id}` against a registration outside the token's allowed team scope. 6. 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`
- CVSS 3.1
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
- Severity from
- GitHub (reviewed advisory)
More IBM advisories
All IBM| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Aug 25 | Parse-gap bypasses in mcp-context-forge: SQL Sanitizer (privesc/DROP/mass-DELETE) and resource_filter SSRF | High8.8 | v1.0.7 |
| Aug 25 | Server-Side Request Forgery (SSRF) in url_to_markdown_server via Unvalidated URL Fetching | Critical9.1 | v1.0.7 |
| Aug 25 | Server-Side Request Forgery (SSRF) in mcp-rss-search via Unvalidated URL Fetching | High8.6 | v1.0.7 |
| Aug 25 | Session auth-context reuse ignores JWT exp — expired JWT replayable within session_auth_reuse_ttl | Medium | v1.0.5 |
| Aug 25 | Cross-tenant read of plugin-binding policies (BOLA) in ContextForge MCP Gateway | High | v1.0.5 |
| Aug 25 | Default JWT Secret in Docker Compose Enables Forged Platform-Admin Tokens | Critical9.8 | v1.0.7 |