{"id":"PYSEC-2026-4109","summary":"MySQL MCP Server: Missing Origin/Host Validation in SSE Transport Enables Unauthenticated SQL Execution (DNS Rebinding / Direct Exposure)","details":"## Summary\n\nIn SSE/HTTP transport mode, `mysql_mcp_server` constructs `SseServerTransport` without passing `security_settings`. As a result, the MCP Python SDK's DNS-rebinding protection (Origin/Host header validation) is disabled; the Starlette application has no CORS or TrustedHost middleware; and the service binds to `0.0.0.0` by default with no authentication on any route.\n\n**Trigger condition:** `MCP_TRANSPORT=sse`. The default stdio mode is not affected.\n\n## Attack Scenarios\n\n**Scenario A — Direct exposure:** Any network attacker can invoke `execute_sql` to run arbitrary SQL without credentials → full data dump, and via MySQL `FILE` privileges, arbitrary file read/write and RCE.\n\n**Scenario B — DNS rebinding (local bind):** An attacker lures a victim's browser to a malicious page, rebinds their domain to `127.0.0.1`, and uses the browser as a proxy to invoke `execute_sql` as same-origin.\n\n## Root Cause\n\nIn `src/mysql_mcp_server/server.py`:\n\n1. `SseServerTransport` is constructed without `security_settings` — the SDK defaults `enable_dns_rebinding_protection` to `False`.\n2. The Starlette app has no CORS or TrustedHost middleware.\n3. All three routes (`/`, `/sse`, `/messages/`) are unauthenticated.\n4. The service binds to `0.0.0.0` by default.\n5. The sink is `cursor.execute(query)` with a fully attacker-controlled query.\n\n## Impact\n\n- Unauthenticated arbitrary SQL execution against the configured database\n- Full data exfiltration and modification\n- If the MySQL account holds `FILE` privilege: arbitrary file read (`LOAD_FILE`) and write (`INTO OUTFILE`) — potential RCE via webshell drop\n- Internet-wide scanning has identified 25 publicly reachable SSE instances of this project\n\n## Fix\n\nReleased in v0.4.2: DNS-rebinding protection is now enabled by passing `TransportSecuritySettings(enable_dns_rebinding_protection=True)` to `SseServerTransport`, and the documented recommended bind address is `127.0.0.1`.\n\n## Credits\n\nDiscovered by Huanchen, SongWu (JHU), and BrookeYangRui (JHU).","aliases":["CVE-2026-59971","GHSA-rqfv-2mw9-78g2"],"modified":"2026-10-01T17:45:11.049833059Z","published":"2026-10-01T16:38:30.553913Z","references":[{"type":"WEB","url":"https://github.com/designcomputer/mysql_mcp_server/security/advisories/GHSA-rqfv-2mw9-78g2"},{"type":"WEB","url":"https://github.com/designcomputer/mysql_mcp_server/issues/92"},{"type":"PACKAGE","url":"https://github.com/designcomputer/mysql_mcp_server"},{"type":"WEB","url":"https://github.com/designcomputer/mysql_mcp_server/releases/tag/v0.4.2"},{"type":"PACKAGE","url":"https://pypi.org/project/mysql-mcp-server"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-rqfv-2mw9-78g2"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-59971"}],"affected":[{"package":{"name":"mysql-mcp-server","ecosystem":"PyPI","purl":"pkg:pypi/mysql-mcp-server"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.4.2"}]}],"versions":["0.1.0","0.1.2","0.2.0","0.2.1","0.2.2","0.3.0","0.3.1","0.4.0","0.4.1"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/mysql-mcp-server/PYSEC-2026-4109.yaml"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"}]}