The Cluster Closes With Two 10.0s: Open SQL in MySQL MCP and an Escaped Sandbox at IBM
Two CVE records published September 15 complete the mid-September cluster of unauthenticated MCP flaws this site has been tracking through Bifrost, gitlab-mcp, and LiteLLM — and both score the maximum. CVE-2026-59971 exposes mysql-mcp-server's execute_sql tool with no authentication whenever the SSE transport is enabled, and CVE-2026-53710 escapes the RestrictedPython sandbox in IBM Context Forge's Python sandbox server through a raw getattr the policy layer never mediated. Both are CVSS 3.1 10.0 with scope changed.
Neither NVD record has completed NVD analysis — at publication the MySQL record sat at “Awaiting Analysis” and the Context Forge record at “Deferred” — so both scores are the assigners' own. The more operationally interesting dates are older than the CVE records: the MySQL advisory and its 0.4.2 fix date to June 21, and the Context Forge advisory to August 24, with its 1.0.2 fix. The catalogue lagged the patches by eight to twelve weeks, which is worth remembering the next time a scan comes back clean on the grounds that no CVE exists yet.
An SQL tool with no authentication and two ways to reach it
CVE-2026-59971 (CWE-306, missing authentication) is a transport-configuration failure in designcomputer/mysql_mcp_server before 0.4.2. Setting MCP_TRANSPORT=sse builds the SseServerTransport without security_settings — the MCP Python SDK defaults DNS-rebinding protection to off — while the Starlette application mounts /, /sse, and /messages/ with no authentication, no CORS or TrustedHost middleware, and a default bind of 0.0.0.0. The sink is cursor.execute(query) with a fully attacker-controlled query. The default stdio transport is not affected.
The advisory documents two attack paths. Direct exposure is the obvious one: anyone who can reach the port invokes execute_sql without credentials, for full disclosure and modification of the configured database. DNS rebinding is the subtler one: a victim visits an attacker page, the attacker's domain re-resolves to loopback, and the browser relays same-origin requests into a locally bound service the network never exposed. The same rebinding class drove the dbhub read-only bypasses and the gitlab-mcp Streamable HTTP flaw covered here previously — the SDK protection exists, but each server has to switch it on, and several did not.
What the MySQL account is allowed to do bounds the damage, and FILE privileges widen it substantially. With them, LOAD_FILE reads server files and INTO OUTFILE writes them, which the advisory and the Johns Hopkins researchers' issue #92 walk all the way to webshell-class code execution. The advisory notes internet-wide scanning found 25 publicly reachable SSE instances of the project — exposure, not confirmed compromise, but a no-auth SQL endpoint does not need volume.
The fix that is honest about what it does not do
Version 0.4.2 enables TransportSecuritySettings(enable_dns_rebinding_protection=True) on the SSE transport and documents 127.0.0.1 as the recommended bind address. What it does not do is add authentication — and the project says so openly. The current README states that the SSE transport has no built-in authentication, binds 0.0.0.0 by default, accepts connections without credentials, and must sit behind a reverse proxy that enforces authentication when exposed beyond localhost.
That honesty is rarer than it should be, and it changes the remediation. Upgrading to 0.4.2 (current release 0.4.4 on PyPI) closes the rebinding path but leaves the direct-exposure path exactly where the operator's configuration puts it. A version pin without a bind-address change and an authenticating proxy is an incomplete fix wearing a patched version number. Treat the advisory's credits — Johns Hopkins researchers on issue #92 — as a reminder that the FILE-privilege-to-webshell chain was demonstrated, not theorized.
A substring scan versus a string concatenation
CVE-2026-53710 (CWE-94 code injection, plus CWE-693 protection-mechanism failure) breaks the RestrictedPython sandbox in the python_sandbox_server subproject of IBM/mcp-context-forge (pip package mcp-contextforge-gateway through 1.0.1), in mcp-servers/python/python_sandbox_server/src/python_sandbox_server/server_fastmcp.py. Three compounding weaknesses, per the August 24 advisory: raw getattr (and setattr) exposed in safe_builtins, bypassing the _getattr_ mediation RestrictedPython's guarantees rest on; a validate_code check that substring-scanned for literal dangerous dunder names; and an execute_code MCP tool reachable over HTTP/SSE transport with no authentication layer.
The bypass is a textbook category error: a list of forbidden names treated as a security boundary. The payload never spells a banned name — it constructs dunder attributes at runtime by concatenating innocuous fragments, then walks the Python class hierarchy through the exposed getattr until it reaches subprocess.Popen. The advisory's proof of concept ran against the real pinned sandbox path: validation reported the payload clean, and the marker command executed. The advisory scores it Critical 9.0 over HTTP transport with a High 8.8 floor for stdio-only deployments; NVD carries 10.0.
Version 1.0.2 removes getattr and setattr from safe_builtins, adds guarded wrappers, replaces the substring scan with an ast.walk() over attribute nodes, and requires a SANDBOX_API_TOKEN of at least 32 characters on the HTTP transport. Two caveats from the advisory deserve preservation: the finding covers the sandbox subproject, not the core Context Forge gateway or proxy components; and the Critical score assumes HTTP reachability, so stdio-only deployments face the smaller vector.
What defenders should do now
- Upgrade
mysql-mcp-serverto 0.4.2 or later (0.4.4 current), then keep going. The upgrade closes DNS rebinding only. Bind SSE to loopback and front any non-local exposure with an authenticating reverse proxy — the README names nginx, Caddy, or Traefik with enforced authentication. - Assume unauthenticated exposure windows mean database and file exposure. If an affected SSE instance was reachable, audit for unexpected queries, new tables or users,
INTO OUTFILEartifacts, and webshell indicators; scope the MySQL account down and revokeFILEwhere it is not needed. - Upgrade
mcp-contextforge-gateway's sandbox server to 1.0.2 or later and set a longSANDBOX_API_TOKEN. Prefer stdio-only deployment for the sandbox component; if HTTP/SSE is required, authenticate everytools/callpath and isolate the host from mounts and internal networks worth pivoting into. - Grep your own RestrictedPython (or any allowlist) integrations for the same two errors. Raw reflective builtins (
getattr,setattr) inside the sandbox, and substring or blocklist validation of code text, are the exact combination that keeps producing escapes. Parse-then-enforce beats scan-for-names. - Treat SDK security defaults as opt-in until verified. The rebinding protection existed in the MCP Python SDK for both of these SSE exposures; neither server enabled it. For every MCP server you run over a network transport, verify Origin/Host validation, authentication, and bind address in the running configuration — not the framework's documentation.
- Close the cluster, not just the CVE. If you run Bifrost, gitlab-mcp, LiteLLM, dbhub, or these two, review all six against the same checklist: unauthenticated transports, rebinding posture, server-side credential exposure, and sandbox boundaries. The September records share a failure mode, not just a month.
The through-line across all six September records is that the protocol's risk lives in defaults, not in exotic prompt injection: transports without authentication, protections present but un-enabled, sandboxes that scan text instead of enforcing structure. LiteLLM's entry remains the one under confirmed active exploitation on CISA's KEV list; these two are the ones where the fix is necessary but, in MySQL's case, explicitly not sufficient. Read the advisory's remediation section, not just its version number.
Sources:
- mysql_mcp_server advisory GHSA-rqfv-2mw9-78g2 — unauthenticated SQL execution over SSE (CVE-2026-59971)
- NVD — CVE-2026-59971 (CVSS 3.1 10.0, CWE-306)
- mysql_mcp_server v0.4.2 release — rebinding protection and loopback bind
- mysql_mcp_server issue #92 — FILE-privilege file access to webshell chain
- PyPI — mysql-mcp-server (0.4.4 current)
- mcp-context-forge advisory GHSA-xm98-3vcf-fph7 — RestrictedPython sandbox bypass (CVE-2026-53710)
- NVD — CVE-2026-53710 (CVSS 3.1 10.0, CWE-94)
- mcp-context-forge v1.0.2 release — sandbox fix
- al-ice.ai — Bifrost's unauthenticated RCE paths (CVE-2026-90898)
- al-ice.ai — gitlab-mcp unauthenticated file read and PAT exfiltration
- al-ice.ai — LiteLLM MCP auth bypass on CISA KEV (CVE-2026-59822)
- al-ice.ai — dbhub read-only bypass and DNS rebinding