fix(auth): block wildcard "*" configuration scope on connections - #5021
Open
0xcucumbersalad wants to merge 1 commit into
Open
fix(auth): block wildcard "*" configuration scope on connections#50210xcucumbersalad wants to merge 1 commit into
0xcucumbersalad wants to merge 1 commit into
Conversation
0xcucumbersalad
force-pushed
the
fix/block-wildcard-connection-scopes
branch
from
July 22, 2026 11:04
2d92a57 to
729dbe3
Compare
A connection whose configuration_scopes contained the literal "*" caused
extractConnectionPermissions to emit `{"*":["*"]}`, which is embedded into
the outbound x-mesh-token JWT. Downstream checkApiKeyPermission treats that
as unconditional "all resources, all tools" access, bypassing every role
check. Any org member could create such a connection, harvest the resulting
wildcard mesh JWT, and replay it to reach admin/owner-only tools
(e.g. API_KEY_CREATE) - a privilege escalation from a plain user/self-signup.
The wildcard could arrive either in the request body or be self-reported by
a (potentially attacker-controlled) target MCP server during tool discovery,
so enforcement lives at the shared choke points rather than the request body.
Defense-in-depth:
- validateConfiguration now rejects any "*" scope (assertNoWildcardScopes),
failing fast at connection create/update before it can be stored. This
covers both the request-body and server-reported paths.
- extractConnectionPermissions no longer expands "*" into a wildcard grant,
so any already-persisted "*" can never mint the escalation-enabling JWT.
Legitimate connection scopes are always resource-scoped ("KEY::SCOPE") and
only grant access to the referenced connection; the genuine full-access
credential path goes through API key creation directly, not connection scopes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0xcucumbersalad
force-pushed
the
fix/block-wildcard-connection-scopes
branch
from
July 22, 2026 11:08
729dbe3 to
927e158
Compare
Contributor
Author
|
Step 1 — signin with user role account Step 2 — get org slug Step 3 — create malicious connection Step 4 — trigger outbound proxy (captured by your listener on port 9999) Step 5 — replay stolen JWT to mint a persistent wildcard API key |
hugo-ccabral
approved these changes
Jul 22, 2026
This was referenced Jul 30, 2026
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.
Summary
Blocks a privilege-escalation path where a plain
user-role member (or a brand-new self-signup) could obtain unconditional admin/owner-equivalent access.A connection whose
configuration_scopescontained the literal"*"causedextractConnectionPermissionsto emit{"*":["*"]}, which is embedded into the outboundx-mesh-tokenJWT (mcp-clients/outbound/headers.ts). DownstreamcheckApiKeyPermissiontreats{"*":["*"]}as all resources, all tools, bypassing every role check. So any org member could:configuration_scopes: ["*"](allowed foruserrole viaconnections:manage),x-mesh-token,API_KEY_CREATE, minting a persistent wildcard API key.The wildcard could arrive either in the request body or be self-reported by a (potentially attacker-controlled) target MCP server during tool discovery — the server-reported scopes win the ternary in
create.ts. So enforcement lives at the shared choke points, not the request body.Changes
Defense-in-depth, two layers:
validateConfigurationnow calls a newassertNoWildcardScopes()that throws on any"*"scope. Runs in bothCOLLECTION_CONNECTIONS_CREATEandCOLLECTION_CONNECTIONS_UPDATE, so the wildcard can never be stored — covering both the request-body and server-reported paths.extractConnectionPermissionsno longer expands"*"into a wildcard grant, so any already-persisted"*"(pre-fix data, or a path that skipped validation) can never mint the escalation-enabling JWT.Legitimate connection scopes are always resource-scoped (
"KEY::SCOPE") and only grant access to the referenced connection. The genuine full-access credential path (per-run sandbox keys) goes through API-key creation directly, not connection configuration scopes — so nothing legitimate relies on the wildcard connection scope.Testing
apps/mesh/src/auth/configuration-scopes.test.ts(5 tests) covering rejection, the grant-time backstop, and that legitimate"KEY::SCOPE"scopes still map correctly. 5 pass.tsc --noEmit: zero errors in the changed files. (The one remaining repo-wide error is a pre-existingajv8.18-vs-8.20 duplicate-version clash innode_modules, unrelated to this change.)Notes / follow-ups
"*"stored will have any future config-touching update rejected until the scope is cleaned up. Intentional — and the grant-time backstop already neutralizes such connections regardless.aud/purposeclaim) — and theconnection_urlSSRF remain separate, larger hardening items tracked elsewhere.Summary by cubic
Block the
"*"configuration scope on connections and stop wildcard grant minting to prevent all‑accessx-mesh-tokenescalation. Closes a path where plain users could bypass role checks.Bug Fixes
"*"viaassertNoWildcardScopesinvalidateConfigurationon create/update (covers body and server‑reported scopes)."*"inextractConnectionPermissions; legacy"*"yields no grant.getReferencedConnectionIdsexcludes"*"; added focused unit tests for rejection and"KEY::SCOPE"mapping.Migration
"*"must remove it before updating; tokens from such connections no longer get wildcard access.Written for commit 927e158. Summary will update on new commits.