MCP vulnerability case study: SQL injection in the Postgres MCP server

MCP vulnerability case study: SQL injection in the Postgres MCP server

A SQL injection vulnerability in Anthropic’s reference Postgres MCP server allowed attackers to terminate the read-only transaction (via stacked statements like “COMMIT;”) and execute arbitrary write statements such as “DROP SCHEMA public CASCADE”. The issue is patched in Zed Industries’ fork @zeddotdev/postgres-context-server v0.1.4 and an unreleased reference fix; affected packages remain archived but still widely downloaded. #COMMIT #DROP_SCHEMA

Keypoints

  • The Anthropic reference Postgres MCP server wrapped user-supplied SQL in a “BEGIN TRANSACTION READ ONLY” but allowed multiple semicolon-delimited statements, enabling SQL injection.
  • An attacker can stack statements to issue COMMIT and then destructive commands (e.g., DROP SCHEMA public CASCADE), escaping the read-only protection and deleting data.
  • Session state changes (e.g., SET statement_timeout) can persist on pooled connections, enabling denial or disruption of subsequent queries from other users.
  • Mitigations include using least-privilege database users, prepared statements (which disallow multiple statements), and recycling connections per request.
  • Zed Industries released a patched fork (@zeddotdev/postgres-context-server v0.1.4); Anthropic archived the reference server but the NPM/Docker packages remain in use and unpatched.
  • Timeline: vulnerable release in Nov 2024, independent report in Nov 2024, Datadog report and patch submissions in Apr 2025, Zed Industries fix Apr 9, 2025, Anthropic archived repository and fixed upstream May 29, 2025.
  • This vulnerability exemplifies classic OWASP Top 10 issues (SQL injection, session management) applied to MCP servers and agentic AI tooling.

MITRE Techniques

  • [T1190] Exploit Public-Facing Application – The MCP server accepted user-supplied SQL queries and allowed stacked statements; “COMMIT; DROP SCHEMA public CASCADE;” demonstrates exploitation of input handling to run arbitrary SQL.
  • [T1059] Command and Scripting Interpreter – SQL statements provided by an attacker were executed by the database engine after terminating the read-only transaction: “‘COMMIT; DROP SCHEMA public CASCADE;’”
  • [T1505] Server Software Component Modification – Changing session state (e.g., “SET statement_timeout TO 1;”) via injected SQL altered connection behavior affecting other users: “‘COMMIT; SET statement_timeout TO 1;’”
  • [T1609] Denial of Service – Modifying session variables like statement_timeout caused subsequent queries to fail (e.g., SELECT pg_sleep(1) resulting in timeout), disrupting availability: “‘ERROR: canceling statement due to statement timeout’”.

Indicators of Compromise

  • [SQL Statements] Malicious injected queries – examples: “COMMIT; DROP SCHEMA public CASCADE;”, “COMMIT; SET statement_timeout TO 1;”.
  • [Package Names] Affected/unpatched packages – @modelcontextprotocol/server-postgres v0.6.2 (archived/unpatched on NPM), mcp/postgres Docker image (unpatched on Docker Hub).
  • [Patched Package] Fixed fork – @zeddotdev/postgres-context-server v0.1.4 (contains prepared-statement and connection-recycle patch).
  • [Repository/POC] Proof of concept location – https://github.com/DataDog/security-labs-pocs/tree/main/proof-of-concept-exploits/postgres-mcp


Read more: https://securitylabs.datadoghq.com/articles/mcp-vulnerability-case-study-SQL-injection-in-the-postgresql-mcp-server/