Broken Acess Control in Team Join Approval Flow
MediumPublished Aug 25, 2026
### Summary The team’s approval to join flow fails to properly validate the user’s privileges over the target team. ### Details The approval flow requires the caller to be the owner of the `team_id` path parameter, but the approval code ignores that parameter when loading the join request. `TeamManagementService.approve_join_request` looks up the request only by `request_id`, then adds the member to `join_request.team_id` and commits. If a team owner calls the endpoint with their own `team_id` but with a `request_id` belonging to some other team, the service approves the other team’s request and adds the user to that team, despite the caller not having any privileges there. ### PoC 1. Attacker obtains an authenticated account with `teams.manage_members` capability and owner role on at least one team they control (Team A). 2. Attacker learns or guesses a valid pending `request_id` belonging to another team (Team B), e.g., "ask to" join response. <img width="1221" height="423" alt="image" src="https://github.com/user-attachments/assets/4ee9cc0f-6848-417f-a642-acf2561f2272" /> 3. Attacker sends `POST /admin/teams/{teamA_id}/join-requests/{requestB_id}/approve` with their valid auth...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| mcp-contextforge-gateway PyPI | < v1.0.6 | v1.0.6 |
Details and references
### Summary The team’s approval to join flow fails to properly validate the user’s privileges over the target team. ### Details The approval flow requires the caller to be the owner of the `team_id` path parameter, but the approval code ignores that parameter when loading the join request. `TeamManagementService.approve_join_request` looks up the request only by `request_id`, then adds the member to `join_request.team_id` and commits. If a team owner calls the endpoint with their own `team_id` but with a `request_id` belonging to some other team, the service approves the other team’s request and adds the user to that team, despite the caller not having any privileges there. ### PoC 1. Attacker obtains an authenticated account with `teams.manage_members` capability and owner role on at least one team they control (Team A). 2. Attacker learns or guesses a valid pending `request_id` belonging to another team (Team B), e.g., "ask to" join response. <img width="1221" height="423" alt="image" src="https://github.com/user-attachments/assets/4ee9cc0f-6848-417f-a642-acf2561f2272" /> 3. Attacker sends `POST /admin/teams/{teamA_id}/join-requests/{requestB_id}/approve` with their valid auth token. 4. The router validates ownership only for `teamA_id` and calls `approve_join_request(request_id, approved_by=attacker_email)` without binding `request_id` to `teamA_id`. 5. Service loads join request by `request_id` only, then creates membership and RBAC assignment for `join_request.team_id` (Team B), marking request approved. 6. Result: unauthorized cross-team membership approval occurs; attacker has modified Team B’s access-control state despite lacking ownership/privileges in Team B. ``` POST /admin/teams/{teamA_id}/join-requests/{requestB_id}/approve HTTP/1.1 Host: 127.0.0.1:8000 Content-Length: 0 X-CSRF-Token: <replace_with_token> HX-Current-URL: http://127.0.0.1:8000/admin/#teams HX-Request: true User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Content-Type: application/x-www-form-urlencoded Origin: http://127.0.0.1:8000 Referer: http://127.0.0.1:8000/admin/ Accept-Encoding: gzip, deflate, br Cookie: mcpgateway_csrf_token=<replace_with_token>; jwt_token=<replace_with_jwt> ``` ### Impact This is an authorization logic flaw enabling any team owner to approve memberships for teams they do not control. Andrea `zi0Black` Cappa @ Aptos Labs
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-284
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 | Scoped admin OAuth DCR endpoints ignore token_teams restrictions and expose global registered clients | Medium6.4 | 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 |