All posts
Scope Drift

MCP Toolbox: A Tool Path Was Never a Scope Boundary

CVE-2026-11720 lets a path parameter escape operator-declared tool scope in Google's official MCP Toolbox, forwarding downstream credentials off-path

Securityv0 Intelligence Team OWASP: ASI03 sv0 finding: scope_drift
mcp scope-drift google-mcp-toolbox path-traversal cve-2026-11720 credential-forwarding

The Incident

CVE-2026-11720 is a critical path-traversal vulnerability in the HTTP tool URL builder of googleapis/mcp-toolbox — Google’s official Model Context Protocol server for databases, formerly Gen AI Toolbox for Databases — disclosed as GHSA-vwxw-jrg6-9jxv in late June 2026 and fixed in v1.3.0. The Toolbox lets AI agents (Claude, Gemini CLI, custom LangGraph deployments) reach SQL, NoSQL, BigQuery, and Postgres via operator-declared tools; the HTTP tool type wraps arbitrary REST endpoints and forwards operator-configured credentials on the agent’s behalf. In vulnerable releases the URL builder substituted user-controlled path parameters into the configured tool path and passed the result through Go’s url.ResolveReference, which normalizes dot segments (.. and their percent-encoded forms) during resolution. A caller supplying a path parameter with traversal sequences could escape the operator’s declared path scope — a tool declared as /api/v1/users/{id} could be coerced to reach /admin/secrets on the same host, with the tool’s configured downstream credentials attached to the request. The advisory carries a CVSS 4.0 base score of 9.3 (Critical); there are no public reports of in-the-wild exploitation.

MITRE ATT&CK coverage: T1190 (Exploit Public-Facing Application), T1552 (Unsecured Credentials), T1078.004 (Cloud Accounts).

The Authority Path That Failed

The identity that carried execution authority at the moment of failure was the Toolbox’s configured downstream credential — a non-human identity held by the Toolbox process on behalf of the HTTP tool. Its held scope was whatever the downstream API grants that credential, which for most production tokens is per-service, not per-endpoint. Its exercised scope was meant to be constrained to the operator’s tool template — say, /api/v1/users/{id} — by the URL builder alone. That builder assumed a net/url scheme, host, and userinfo check plus ResolveReference would keep the constructed URL inside the declared path. Because ResolveReference normalizes dot segments, one crafted path parameter closed the gap: the credential authorized what the operator never declared.

The trust anchor that failed first was the implicit equation of “tool definition” with “scope boundary.” Operators wrote path templates as if they were guards. They were guidance for a URL builder that happened to also be the enforcer — and the enforcer had a bug. The gap between held authority (per-service token) and exercised authority (endpoint declared in tools.yaml) was knowable at deploy time, but only if something observed the credential’s actual reach, not the tool config.

SecurityV0 Perspective

This is a textbook scope_drift finding. The failure that publishes for our readers is not the CVE itself — it’s that Google’s reference MCP server for enterprise data treated a tool’s path template as its scope boundary while relying on a single URL-parsing routine to enforce it. The evidence pack SecurityV0 would produce compares the tool definitions loaded from tools.yaml against the outbound requests the Toolbox actually made in production: declared tool identity, declared host and base path, configured credential fingerprint, and per-tool observed request paths grouped by outcome. The pre-exfiltration question the pack answers is “which tools exercised paths outside their declared base?” — a check that fires independently of framework version. The post-exfiltration forensic question is “which requests carried a forwarded credential to a path the operator never authorized, and what did the downstream API return?”

CVE-2026-11720 does not stand alone. It sits in a same-window batch of critical mcp-toolbox advisories — DNS-rebinding via permissive CORS (CVE-2026-9739), an issuer-check auth bypass in validateOpaqueToken (CVE-2026-11718), and an authorization bypass across the legacy MCP protocol handlers (CVE-2026-11719). Treated together, they mark the MCP server layer as an actively moving scope boundary. Operators inheriting that boundary need a check that runs above the framework, not inside it.

What To Do

  • Upgrade googleapis/mcp-toolbox to v1.3.0 or later. The fix rejects dot-segment path parameters at the URL builder, enforces a base-path scope check on the resolved URL, and adds pathEscape / queryEscape template helpers for parameter substitution. Pin the version in your deployment manifest; do not float a major.

  • Enumerate the tokens each HTTP tool forwards, and re-scope them. For every http tool in your tools.yaml, list the credential the Toolbox forwards to the downstream host. If that token can reach any endpoint on the host other than the ones the tool declares, replace it with one that can’t — a per-endpoint API key, an IAM role bound to the tool’s endpoint prefix, or a service account scoped by the downstream’s own policy.

  • Emit the declared vs. exercised path for every tool call. Have the Toolbox (or a sidecar on egress) log tool_name, declared_base_path, resolved_request_path, and credential_fingerprint. Alert whenever resolved_request_path does not start with declared_base_path on the same host. This check survives future URL-builder bugs.

  • Do not expose the MCP endpoint without client auth. The sibling advisories in this batch — DNS-rebinding via wildcard CORS and issuer-check bypass in validateOpaqueToken — assume a Toolbox that trusted the network or a header. Front the MCP endpoint with mutual TLS, an authenticating reverse proxy, or a signed-token check verified independently of the Toolbox itself.

  • Treat every MCP tool definition as a policy artifact, not a configuration file. Review tools.yaml in the same code-review path as IAM policies: named owner, change log, deploy gate. Any diff that widens a declared path or attaches a broader credential should require the same approval as adding a bucket-write policy.

Sources