Answers · MCP security
Our agent uses the AWS Labs Postgres, MySQL or DocumentDB MCP server in its default read-only mode. Which advisories showed that read-only mode could be bypassed, which versions fix them, and is read-only mode safe to rely on now?
Last updated
TL;DR: Upgrade to awslabs.postgres-mcp-server 1.1.7 or later, awslabs.mysql-mcp-server 1.0.23 or later and awslabs.documentdb-mcp-server 1.0.12 or later, and don't treat read-only mode as the boundary even then. Four advisories showed SQL or pipelines getting past it: in Postgres, statements its blocklist missed could change data (CVE-2026-85787) and COPY ... TO PROGRAM could run operating-system commands on a self-managed server when the connected role was a superuser or held pg_execute_server_program (CVE-2026-87911, critical, CVSS 9.6); in MySQL, comments placed between keywords slipped past text patterns (CVE-2026-85788); in DocumentDB, the aggregate tool accepted $out and $merge stages that write (CVE-2026-18954). The attacker doesn't need access to the server: Postgres advisories describe crafted SQL placed in content an authenticated user's agent processes, and the MySQL one names prompt injection. AWS's own READMEs now call read-only mode best effort and say the database role you connect with is the real boundary, so connect with a role that can only read.
What should I check, step by step?
1. Check the installed versions: postgres-mcp-server before 1.1.7, mysql-mcp-server 1.0.21 or earlier (there was no 1.0.22) and documentdb-mcp-server before 1.0.12 are affected. The newest on PyPI on November 11, 2026 were 1.2.4, 1.1.5 and 2.0.1.
- Look at the dates, not just the CVEs: the fixed releases came out months before the advisories (Postgres 1.1.7 on June 25, MySQL 1.0.23 on July 2, DocumentDB 1.0.12 on April 8, 2026), so a pinned install that was never upgraded is the usual way to still be exposed.
- Connect each server with a role that can only read: in Postgres, CONNECT, USAGE and SELECT on the schemas the agent needs, read-only transactions forced at the role level, and not a superuser, rds_superuser or the cluster master user. In MySQL, SELECT only. In DocumentDB, a user without write privileges.
- In Postgres, never grant the agent's role pg_execute_server_program, pg_read_server_files or pg_write_server_files. PostgreSQL's docs say they allow running programs and reading or writing files on the database server and could be used to gain superuser-level access.
- Don't add --allow_write_query to make a demo work and leave it there. Without it the servers run their read-only checks; with it they run whatever the role permits.
- Treat every value the agent reads from the database, tickets, documents or web pages as untrusted input that may contain SQL aimed at the next query.
- Point read-only agents at a read replica or reader endpoint where you have one, so a missed write has nowhere to land.
Which AWS Labs Postgres, MySQL and DocumentDB MCP server advisories bypassed read-only mode, and which versions fix them?
Postgres, CVE-2026-85787 (GHSA-pwr4-hmph-gqgc, medium, CVSS 3.1 6.5, published September 4, 2026): an incomplete list of disallowed inputs in the SQL validation component let crafted SQL modify data beyond the read-only scope. Postgres, CVE-2026-87911 (GHSA-fph8-pg5w-78fv, critical, CVSS 3.1 9.6, published September 9, 2026): the read-only check didn't block every SQL verb that performs system-level operations, so a COPY ... TO PROGRAM statement could execute operating-system commands on the host of a self-managed PostgreSQL server, when the PG_WIRE_PROTOCOL connection method was used with a role holding superuser or pg_execute_server_program. Both affect versions before 1.1.7.
- MySQL, CVE-2026-85788 (GHSA-x25m-ph3m-3r9q, medium, CVSS 3.1 5.5, published September 9, 2026): read-only enforcement matched SQL text with patterns that expected literal whitespace between keywords, and MySQL treats comments as whitespace, so SQL interleaved with comments passed the check and still ran. Its impact depends on the MySQL user holding the FILE privilege. It affects 1.0.21 and earlier; the fix in 1.0.23 strips comments before matching and rejects MySQL conditional comments, the /*! ... */ form that MySQL's documentation says the server parses and executes.
- DocumentDB, CVE-2026-18954 (GHSA-j694-4m5j-w8hc, medium, CVSS 3.1 5.5, published August 5, 2026): in the default read-only mode the insert, update and delete tools refused writes, but the aggregate tool didn't check pipeline stages, so $out and $merge wrote to the database anyway. It affects versions before 1.0.12.
How can SQL or a pipeline get past an MCP database server's read-only mode without anyone logging in?
The Postgres and MySQL bypasses don't need anyone to log in to the MCP server. The Postgres advisories describe crafted SQL placed in content that is processed when an authenticated user interacts with the server, and the MySQL advisory says anyone able to influence the SQL string, including through prompt injection against the model driving the client, can submit statements the check misses. A comment field, a support ticket or a web page the agent reads is enough to carry the instruction.
- PostgreSQL's documentation shows why the role matters. COPY with PROGRAM runs the command on the database server as the operating-system user PostgreSQL runs as, and only superusers or roles granted pg_execute_server_program (or the server file-access roles) may use it. The advisory says users who connected the MCP server with a minimal-privilege role weren't affected, because the database itself denied the operation.
- The same pattern holds for the other bypasses. A data-changing statement, a FILE-based write or an aggregation with $out or $merge all need a role that can write; the DocumentDB advisory's own workaround is a database user without write privileges. Each bypass got past the MCP server's check and then depended on what the connected role was allowed to do.
Is an AWS Labs MCP database server's read-only mode a security boundary?
AWS says no, in its own words. The MySQL server's README says its read-only mode "is a best-effort SQL-text safeguard, not a security boundary" and that the actual boundary is the database role you connect with; it says the Postgres, MSSQL and Oracle sibling servers carry the same caveat. Its table of what the check doesn't catch includes quoted-identifier tricks and mutating verbs added in future MySQL releases.
- The current Postgres README describes a stronger guard: each query is parsed with PostgreSQL's own parser, only read statement shapes are allowed, multi-statement input is rejected, it fails closed on parse errors, and command execution, server file access and network calls such as dblink are always refused. It still calls the enforcement best effort and recommends a minimal-privilege role, with no pg_read_server_files, pg_write_server_files or pg_execute_server_program, and no USAGE on foreign data wrappers or foreign servers.
- So keep both layers. The server's check gives a fast, readable refusal and catches mistakes; the role's grants decide what can actually happen. When you need the agent to write, scope the role to the tables it needs and put a person in front of each write query rather than switching the whole server to --allow_write_query.
How do I ask Rightshold about this (free, no key)?
Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “My agent wants to run one UPDATE through the AWS Labs Postgres MCP server, which we keep read-only otherwise. Ask me to approve that exact statement first, with a record I can check, before we run it once with a write-scoped role.”
{
"tool": "request_human_approval",
"arguments": {
"action": {
"tool": "run_query",
"server": "awslabs.postgres-mcp-server",
"server_version": "1.2.4",
"sql": "UPDATE orders SET status = 'shipped' WHERE id = 1042",
"role": "mcp_orders_writer"
},
"summary": "Run one UPDATE on orders (id 1042) via the Postgres MCP server",
"expires_in_minutes": 30
}
}- Needs a key for your account. It hashes the action details and returns an approval id and a one-time token for the owner. Only the account owner can decide it, with an account key; delegated agent keys are refused, so the agent can't approve its own request. Anyone can check the signed decision free with verify_human_approval, including that the action matches what was approved.
- It doesn't connect to your database, parse the SQL, check your server version or role grants, or stop a query your client sends straight to the MCP server. It only covers calls your agent or harness routes through it first, so keep the read-only role in place either way.
Rightshold isn't affiliated with AWS, the awslabs/mcp project, PostgreSQL or MySQL. It doesn't scan MCP servers, databases or role grants, and an approval record isn't a finding that a query or deployment is safe. Advisory details are as published in the awslabs/mcp repository on GitHub, server behavior as described in the servers' READMEs, database behavior as described in PostgreSQL and MySQL documentation, and release dates as listed on PyPI, all read November 11, 2026; advisories get updated, so confirm fixed versions on the linked pages.
What are the sources?
- awslabs/mcp: GHSA-fph8-pg5w-78fv, postgres-mcp-server read-only bypass enabling OS command execution (CVE-2026-87911)
- awslabs/mcp: GHSA-pwr4-hmph-gqgc, postgres-mcp-server incomplete list of disallowed inputs (CVE-2026-85787)
- awslabs/mcp: GHSA-x25m-ph3m-3r9q, mysql-mcp-server read-only mode circumvented via inline comments (CVE-2026-85788)
- awslabs/mcp: GHSA-j694-4m5j-w8hc, DocumentDB MCP Server aggregation pipeline read-only bypass (CVE-2026-18954)
- awslabs/mcp: Postgres MCP Server README (read-only enforcement, minimal-privilege role)
- awslabs/mcp: MySQL MCP Server README (security model)
- PostgreSQL documentation: COPY
- PostgreSQL documentation: Predefined roles
- MySQL 8.4 Reference Manual: Comments
Related
- Restricting an MCP database tool to read-only queries
- Stopping prompt injection in fetched web and file content from triggering MCP write tools
- Are MCP tool annotations like readOnlyHint a security guarantee?
- Why an MCP server's tool deny list can silently miss dangerous calls
Not legal advice. JSON · Markdown · All answers
Get a free API key in one call
No card and no email needed. 100 free credits; the license and policy checks stay free without a key.
curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_... # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
-H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'
