Skip to content

CVE-2026-14537: Verified Reproduction

CVE-2026-14537: mcp-toolbox authorization bypass: unauthenticated tool invocation via direct HTTP API

CVE-2026-14537 is verified against googleapis/genai-toolbox · github. Affected versions: >= v1.3.0 (2026-05-21) and <= v1.4.0 (2026-06-04). Fixed in v1.5.0 (2026-06-18). Vulnerability class: Auth Bypass. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00318.

REPRO-2026-00318 googleapis/genai-toolbox · github Auth Bypass Aug 1, 2026 CVE entry ↗ .txt
Severity
HIGH
Confidence
HIGH
Reproduced in
37m 46s
Tool calls
197
Spend
$4.34
01 · Overview

What Is CVE-2026-14537?

CVE-2026-14537 is a high-severity Auth Bypass vulnerability affecting googleapis/genai-toolbox >= v1.3.0 (2026-05-21) and <= v1.4.0 (2026-06-04). Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00318).

02 · Severity & CVSS

CVE-2026-14537 Severity

CVE-2026-14537 is rated high severity.

HIGH threat level
Weakness CWE-863 (Incorrect Authorization) — Incorrect Authorization

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected googleapis/genai-toolbox Versions

googleapis/genai-toolbox · github versions >= v1.3.0 (2026-05-21) and <= v1.4.0 (2026-06-04) are affected.

How to Reproduce CVE-2026-14537

$ pruva-verify REPRO-2026-00318
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00318/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-14537

Authorization bypass — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

Unauthenticated POST /api/tool/protected-tool/invoke with JSON body {"sql": "SELECT 'CVE-2026-14537-PWNED' AS marker"} and no Authorization header

Attack chain
  1. POST /api/tool/{toolName}/invoke on mcp-toolbox v1.4.0 started with --enable-api plus an mcpEnabled generic authService; tool protected only by MCP-model scopesRequired
Runnable proof: reproduction_steps.sh
Captured evidence: fixed server
How the agent worked 407 events · 197 tool calls · 38 min
38 minDuration
197Tool calls
68Reasoning steps
407Events
13Dead-ends
Agent activity over 38 min
Policy
1
Support
8
Repro
227
Judge
27
Variant
139
Verify
1
0:0037:32

Root Cause and Exploit Chain for CVE-2026-14537

Versions: v1.3.0 (2026-05-21) through v1.4.0 (2026-06-04).Fixed: in: v1.5.0 (2026-06-18), fix commit

google/mcp-toolbox (repository googleapis/genai-toolbox) versions v1.3.0–v1.4.0 suffer from an incorrect-authorization vulnerability (CWE-863). When the server is configured with an MCP-enabled authorization service (mcpEnabled: true, OAuth scopes via scopesRequired) and the legacy direct HTTP API is enabled (--enable-api), the legacy endpoint POST /api/tool/{toolName}/invoke executes tools without enforcing the MCP authorization policy. An unauthenticated remote attacker can invoke tools that the operator believes are protected by OAuth scopes, because scope enforcement exists only on the /mcp endpoint path.

  • Component: internal/server/api.go (toolInvokeHandler) together with internal/server/server.go (mcpAuthMiddleware mounted only under /mcp).
  • Affected versions: v1.3.0 (2026-05-21) through v1.4.0 (2026-06-04).
  • Fixed in: v1.5.0 (2026-06-18), fix commit a6ff910a602adece11f0a6581d6211e5927f7182 ("fix(server): fail if MCP auth is enabled together with enable-api (#3435)").
  • Risk: high (CVSS 4.0 8.1). Any tool protected solely by the MCP authorization model (an mcpEnabled authService plus tool-level scopesRequired, with no legacy authRequired) is remotely invocable with no credentials at all, including destructive tools (e.g. sqlite-execute-sql, SQL execution tools against production databases).

Impact Parity

  • Disclosed/claimed maximum impact: authorization bypass — unauthenticated remote invocation of scope-protected tools via the direct HTTP API (expected_impact=authz_bypass, surface api_remote).
  • Reproduced impact in this run: identical — HTTP 200 and actual tool execution (arbitrary SQL against the configured SQLite source) via POST /api/tool/protected-tool/invoke with no Authorization header, while the same unauthenticated caller receives HTTP 401 on /mcp.
  • Parity: full.
  • Not demonstrated: nothing beyond the claimed impact (no code execution was claimed or required).

Root Cause

Authorization in mcp-toolbox v1.3.0/v1.4.0 is split across two independent enforcement points:

  1. MCP path (/mcp): mcpAuthMiddleware (internal/server/server.go) validates the Bearer token via ValidateMCPAuth (including authService scopesRequired), and the MCP tools/call handler additionally enforces tool-level scopes through mcputil.ValidateScopes(ctx, tool.GetScopesRequired(), ...) (internal/server/mcp/v20250618/method.go).
  2. Legacy HTTP API path (/api, enabled by --enable-api): the router in internal/server/api.go has no MCP auth middleware, and toolInvokeHandler only enforces the legacy authRequired mechanism (tool.Authorized(verifiedAuthServices)), which returns true unconditionally when a tool declares no authRequired (IsAuthorized: "no authorization requirement"). Tool-level scopesRequired is never consulted on this path.

Consequently, a tool protected only by the modern MCP scope model (scopesRequired, no legacy authRequired) is fully open on the legacy HTTP API: the unauthenticated request passes IsAuthorized([]) and the tool executes. The fix in v1.5.0 does not add scope checks to the legacy endpoint; instead it makes the dangerous configuration fail closed at startup: cmd/root.go and internal/server/server.go (InitializeConfigs) refuse to run when any authService IsMCPEnabled() and EnableAPI are both set ("MCP Auth cannot be enabled together with the legacy HTTP API"), and a new IsMCPEnabled() method was added to the AuthServiceConfig interface for that check.

Fix commit: a6ff910a602adece11f0a6581d6211e5927f7182 (PR #3435).

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh (self-contained; installs Go 1.26.3 if needed, clones/uses the prepared repo cache, builds the real product at v1.4.0 and v1.5.0).
  2. The script starts a local OIDC authorization-server stub (bundle/repro/oidc_stub.py), then launches the real v1.4.0 server with bundle/repro/tools.yaml (generic authService mcpEnabled: true + scopesRequired: [read:files]; tool protected-tool of type sqlite-execute-sql with scopesRequired: [execute:sql] and no authRequired) and flags --enable-api --toolbox-url --port 5000.
  3. It then sends the attacker request POST /api/tool/protected-tool/invoke with body {"sql": "SELECT 'CVE-2026-14537-PWNED' AS marker"} and no Authorization header, followed by a contrast request to /mcp without a token, and finally attempts to start v1.5.0 with the identical config and flags.

Expected evidence:

  • v1.4.0 legacy API: HTTP 200 with the marker CVE-2026-14537-PWNED in the JSON response (tool executed unauthenticated) — vulnerable.
  • v1.4.0 /mcp: HTTP 401 with a WWW-Authenticate challenge — the MCP path enforces authorization correctly.
  • v1.5.0: exits at startup logging "MCP Auth cannot be enabled together with the legacy HTTP API" and never serves the API — fixed (fail closed).

Evidence

  • bundle/logs/reproduction_steps.log — full run transcript.
  • bundle/logs/vuln_server.log — v1.4.0 server startup (MCP auth + legacy API both active).
  • bundle/logs/vuln_api_invoke_status.txt / vuln_api_invoke_body.json — HTTP status and response body of the unauthenticated invoke (200 + marker).
  • bundle/logs/vuln_mcp_noauth_status.txt / vuln_mcp_noauth_body.json — 401 from /mcp without a token (contrast control).
  • bundle/logs/fixed_server.log — v1.5.0 startup refusal message.
  • bundle/logs/oidc_stub.log — OIDC discovery requests made by the server at startup (proves the real MCP auth stack was initialized).
  • bundle/repro/runtime_manifest.json — structured runtime evidence manifest.

Environment: linux/amd64, Go 1.26.3, mcp-toolbox built from source at tags v1.4.0 (d67cfbe8ddc) and v1.5.0, python3 OIDC stub on 127.0.0.1:8099.

Recommendations / Next Steps

  • Upgrade to v1.5.0 or later; do not run --enable-api together with MCP-enabled authorization services on affected versions.
  • Operators on v1.3.0/v1.4.0 who must keep the legacy API should add explicit legacy authRequired entries to every tool (the legacy mechanism is still enforced on /api), or front the server with a proxy that blocks /api.
  • Long-term: the legacy /api endpoints are deprecated; migrate clients to the standard /mcp JSON-RPC endpoint where MCP authorization is enforced.

Additional Notes

  • The reproduction is idempotent: the script rebuilds only when the resolved commit changes, restarts all services on each run, and cleans up background processes via a trap.
  • Edge cases: tools that DO declare legacy authRequired referencing the mcpEnabled generic authService are not bypassed on /api (claims come from the MCP context, which is empty there, yielding 401); the bypass applies to tools protected only via the MCP scope model, which is the configuration the fix commit targets ("clients could potentially bypass MCP authorization policies by using the legacy HTTP API").
  • No public PoC existed; this reproduction was built from the fix-commit analysis of PR #3435.

CVE-2026-14537 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:003:33
0:00
session startedaccounts/fireworks/models/kimi-k3 · CVE-2026-14537 · REPRO-20
0:05
0:06
web search
0:31
0:31
extract_facts
no facts extracted
0:47
0:47
supportclaim_contract
0:59
0:59
1:00
1:09
1:09
1:09
1:14
1:15
$go version 2>&1; which go; ls /pruva/project-cache 2>&1; ls /pruva/project-cache/repo-mirrors 2>&1
0.5s
pruva-command: 1: go: not found
repo-mirrors
1:15
1:20
3:07
$cd /pruva/project-cache && git clone --bare https://github.com/googleapis/genai-toolbox repo-mirrors/mcp-toolbox.git 2>&1 | tail -3; git --git-dir=repo-mirrors/mcp-toolbox.git tag | grep -E 'v1\.[345]\.0'
106.2s
Cloning into bare repository 'repo-mirrors/mcp-toolbox.git'...
v1.3.0
v1.4.0
v1.5.0
3:13
3:14
$git -C /pruva/project-cache clone repo-mirrors/mcp-toolbox.git repo 2>&1 | tail -1; git -C /pruva/project-cache/repo checkout v1.4.0 2>&1 | tail -2; ls /pruva/project-cache/repo
0.7s
done.

HEAD is now at d67cfbe8ddc chore(main): release 1.4.0 (#3301)
AGENTS.md
CHANGELOG.md
CLAUDE.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
3:17
$grep -rn "api/tool" /pruva/project-cache/repo/internal/server/*.go | head -20
0.4s
/pruva/project-cache/repo/internal/server/server_test.go:382:					url:         "/api/toolset",
/pruva/project-cache/repo/internal/server/server_test.go:387:					url:         "/api/tool/tool_one",
/pruva/project-cache/repo/internal/server/server_test.go:392:					url:         "/api/tool/tool_one/invoke",
/pruva/project-cache/repo/internal/server/server_test.go:537:					url:         "/api/toolset",
/pruva/project-cache/repo/internal/server/server_test.go:542:					url:         "/api/tool/tool_one",
/pruva/project-cache/repo/internal/server/server_test.go:549:					url:         "/api/tool/tool_one/invoke",
/pruva/project-cache/repo/internal/server/server_test.go:926:	url := fmt.Sprintf("http://%s:%d/api/tool/list", addr, port)
3:19
$grep -rn "invoke" /pruva/project-cache/repo/internal/server/api.go 2>/dev/null | head; ls /pruva/project-cache/repo/internal/server/
0.4s
47:		r.Post("/invoke", func(w http.ResponseWriter, r *http.Request) { toolInvokeHandler(s, w, r) })
113:// toolInvokeHandler handles the API request to invoke a specific Tool.
115:	ctx, span := s.instrumentation.Tracer.Start(r.Context(), "toolbox/server/tool/invoke")
api.go
api_test.go
common_test.go
config.go
mcp
3:22
3:24
3:33
3:33
$git -C /pruva/project-cache/repo diff v1.4.0 v1.5.0 --stat | tail -30
0.5s
{"cwd":"/workspace","duration_ms":88,"exit_code":0,"stderr":"","stdout":" npm/server-win32-arm64/scripts/downloadBinary.js   |    2 +-\n npm/server-win32-arm64/version.txt                 |    1 -\n npm/server-win32-x64/package-lock.json             |    4 +-\n npm/server-win32-x64/package.json                  |    2 +-\n npm/server-win32-x64/scripts/downloadBinary.js     |    2 +-\n npm/server-win32-x64/version.txt                   |    1 -\n npm/server/README.md                               |    2 +-\n npm/server/package-lock.json                       |   51 +-\n npm/server/package.json                            |   12 +-\n pypi/setup.py                                      |  122 +--\n pypi/src/toolbox_server/__init__.py                |    2 +-\n pypi/tests/__init__.py                             |    1 -\n pypi/tests/{test_wrapper.py => test_main.py}       |    9 +-\n server.json                                        |    4 +-\n .../alloydbainl/alloydb_ai_nl_integration_test.go  |    2 +-\n tests/alloydbainl/alloydb_ai_nl_mcp_test.go        |    4 +-\n tests/auth/auth_integration_test.go                |   37 +-\n tests/bigquery/bigquery_integration_test.go        |    4… [truncated]
08 · How to Fix

How to Fix CVE-2026-14537

Upgrade googleapis/genai-toolbox · github to v1.5.0 (2026-06-18) or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-14537 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-14537

Is CVE-2026-14537 exploitable?

Yes. Pruva independently reproduced CVE-2026-14537 in googleapis/genai-toolbox and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00318).

How severe is CVE-2026-14537?

CVE-2026-14537 is rated high severity.

What type of vulnerability is CVE-2026-14537?

CVE-2026-14537 is classified as CWE-863 (Incorrect Authorization) (Incorrect Authorization), a Auth Bypass vulnerability.

Which versions of googleapis/genai-toolbox are affected by CVE-2026-14537?

googleapis/genai-toolbox >= v1.3.0 (2026-05-21) and <= v1.4.0 (2026-06-04) is affected by CVE-2026-14537.

Is there a fix for CVE-2026-14537?

Yes. CVE-2026-14537 is fixed in googleapis/genai-toolbox v1.5.0 (2026-06-18). Upgrading to the fixed version remediates the issue.

How can I reproduce CVE-2026-14537?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-14537 reproduction verified?

Yes. Pruva reproduced CVE-2026-14537 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-14537

Authoritative sources for CVE-2026-14537 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.