Repository navigation
fix(mcp): deny API key management to team API keys - #78
Merged
Merged
Conversation
A team API key could call list_api_keys, create_api_key and delete_api_key over MCP because authorizeMcpTool returned early for team keys. A leaked key could therefore mint replacement keys for itself or revoke the team's other keys. REST already refuses this with user_auth_required. Deny these three tools to team_key callers in the central MCP policy, returning a user_auth_required tool error. OAuth callers with the api_keys scopes are unaffected. Addresses item 1 of #59.
10 tasks
…key-management # Conflicts: # apps/api/src/mcp/policy.ts # apps/api/src/mcp/server.test.ts # apps/docs/content/docs/developers/mcp.mdx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the high-severity Security item 1 in #59: a team API key could create and delete team keys over MCP.
Problem
authorizeMcpTool(apps/api/src/mcp/policy.ts) returnednull(allowed) for everyteam_keycaller, and thelist_api_keys/create_api_key/delete_api_keyhandlers don't check anything themselves. A leaked key could mint replacement keys for itself, so revoking it wouldn't lock the attacker out, and it could revoke the team's other keys. REST already refuses this:/teams/*returns 403user_auth_requiredto key callers.Fix
As the issue suggests (FrontLit's
apiKeyDeniedTools), the central MCP policy now has ateamKeyDeniedToolsset:list_api_keys,create_api_key,delete_api_key. Ateam_keycaller asking for one of these gets auser_auth_requiredtool error before the handler runs, so no key queries execute. The denial is logged through the existingscopeDecision: "denied"path. OAuth callers still needapi_keys:read/api_keys:write, as before. All other team-key behaviour is unchanged.The check lives in the policy layer rather than in each handler, because every tool already goes through it, so the rule sits in one place next to the scope policy.
Tests (
apps/api/src/mcp/server.test.ts)authorizeMcpTooldenies all three tools to a team key withuser_auth_required, and allows them for OAuth with theapi_keysscopes.tools/callfor all three tools returnsisErrorwithuser_auth_required, andgetApiKeysByTeamId/createApiKey/deleteApiKeyare never called.api_keys:writecan still calldelete_api_key.Docs updated:
apps/docs/.../developers/mcp.mdxandapps/api/docs/mcp-2026-07-28-migration.md.Checks run locally (same steps as CI)
pnpm install --frozen-lockfile,pnpm lint,prettier --check packages apps *.md, the package builds (api-contract, email-editor, email-blocks),pnpm test, andapps/apitsc --noEmit+pnpm typecheck: all pass.Not in this PR
#59 also lists items 2–8: archived-team keys still authenticating, any team member managing keys over REST,
last_used_at, revoked keys being listed, 204 on unknown key delete, the shared org-key display prefix, and stale docs. This PR doesn't fix those, so it doesn't close #59 and leaves the remaining items tracked there.Refs #59