Skip to content

fix(rbac): enforce team-membership check on plugin binding DELETE endpoints#4405

Open
shoummu1 wants to merge 2 commits intomainfrom
fix/plugin-binding-delete-team-membership-check
Open

fix(rbac): enforce team-membership check on plugin binding DELETE endpoints#4405
shoummu1 wants to merge 2 commits intomainfrom
fix/plugin-binding-delete-team-membership-check

Conversation

@shoummu1
Copy link
Copy Markdown
Collaborator

Bug-fix PR

📌 Summary

DELETE /v1/tools/plugin_bindings/{id} and DELETE /v1/tools/plugin_bindings?binding_reference_id=... relied solely on the tools.manage_plugins RBAC permission and did not verify that the caller's team membership overlapped with the binding's team_id. A non-admin holding tools.manage_plugins on any team could delete a binding belonging to a different team by guessing or observing its UUID or external reference ID. The paired upsert endpoint already enforced this check; the delete endpoints did not.

🔗 Related Issue

Closes: #4311

🔁 Reproduction Steps

See #4311.

  1. Authenticate as a non-admin user who holds tools.manage_plugins on team-A.
  2. Obtain the UUID (or binding_reference_id) of a binding that belongs to team-B.
  3. DELETE /v1/tools/plugin_bindings/<team-B-binding-uuid> → binding is deleted despite the caller having no membership in team-B.

🐞 Root Cause

The router handlers (delete_tool_plugin_binding, delete_tool_plugin_bindings_by_reference) forwarded the delete straight to the service layer without extracting the caller's team membership or passing it down. The service methods contained no team filter — they matched only on id / binding_reference_id, making any binding reachable to anyone with the permission.

Affected code:

  • mcpgateway/routers/tool_plugin_bindings.py lines 189–286
  • mcpgateway/services/tool_plugin_binding_service.py delete_binding / delete_bindings_by_reference

💡 Fix Description

Two orthogonal layers of defence, mirroring the existing upsert pattern:

  1. Router-side guard — each delete handler now extracts is_admin and teams from current_user_ctx and computes allowed_teams = None (admin bypass) or set(user_teams) (non-admin). This is passed to the service.

  2. Service-side scoping:

    • delete_binding — checks binding.team_id not in allowed_teams before deleting; raises ToolPluginBindingForbiddenError (mapped to HTTP 403 by the router).
    • delete_bindings_by_reference — applies team_id.in_(allowed_teams) as a SQL filter so foreign-team rows are never fetched or deleted (silent skip, consistent with bulk-operation semantics).

A new ToolPluginBindingForbiddenError exception class carries the denial through the service→router boundary cleanly.

🧪 Verification

Check Command Status
Lint suite make lint
Unit tests make test
Coverage ≥ 90 % make coverage
Plugin-binding tests (76 pass) .venv/bin/pytest tests/unit/mcpgateway/routers/test_tool_plugin_bindings.py tests/unit/mcpgateway/services/test_tool_plugin_binding_service.py -v ✅ 76/76 passed
Non-admin foreign team → 403 test_delete_non_admin_foreign_team_raises_403
Non-admin bulk scoped to own team test_delete_by_reference_non_admin_scoped_to_own_teams

📐 MCP Compliance (if relevant)

  • Matches current MCP spec
  • No breaking change to MCP clients

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • No secrets/credentials committed

@shoummu1 shoummu1 added bug Something isn't working security Improves security plugins labels Apr 23, 2026
…points

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
…endpoints

Signed-off-by: Shoumi <shoumimukherjee@gmail.com>
@shoummu1 shoummu1 force-pushed the fix/plugin-binding-delete-team-membership-check branch from 54c2454 to 98fb711 Compare April 24, 2026 03:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working plugins security Improves security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SECURITY]: tool plugin binding delete endpoints skip team-membership filter

1 participant