Quick Take
- What: CVE-2026-126196 allowed SQL statement smuggling to bypass read-only mode in pgEdge Postgres MCP Server, enabling unauthorized database writes.
- Who is affected: Any deployment of pgEdge Postgres MCP Server version 1.0.0 or earlier that relies on read_only mode as a safety boundary and connects with a role holding write privileges.
- Fixed version: 1.1.0
- What to do: Upgrade to version 1.1.0 or later and review database audit logs for unexpected DDL or DML issued through the MCP connection.
- Severity: High (CVSS 8.1)
In plain English
A security flaw in pgEdge Postgres MCP Server let someone send multiple SQL commands in a single request to a database connection that was supposed to be read-only. By adding extra commands after a semicolon, an attacker could change the connection to read-write mode and then create, modify, or delete database tables. The problem is fixed in version 1.1.0, which now only allows one SQL statement per request on read-only connections.
What you should do: If you use this tool to connect to PostgreSQL databases through AI agents or Model Context Protocol clients, you should upgrade immediately and check your database logs to see if anyone exploited this flaw. If you don’t use pgEdge Postgres MCP Server, you can ignore this.
What happened
pgEdge Postgres MCP Server enables SQL queries against PostgreSQL databases through Model Context Protocol compatible clients. Prior to version 1.1.0, the query_database tool on a read_only connection could send unrecognized statements through pgx Exec without bind parameters, selecting PostgreSQL’s simple query protocol and allowing multiple semicolon-separated statements in one request.
A caller could combine transaction or session state changes with database writes. For example, they could append SET TRANSACTION READ WRITE or COMMIT; BEGIN READ WRITE to a request, then write to the database. The flaw was demonstrated by pgEdge engineering against a throwaway PostgreSQL 17.10 instance, creating, altering and dropping real tables.
The vulnerability had several contributing causes:
- The textual guard matched only the literal strings
transaction_read_onlyanddefault_transaction_read_only, and never checkedREAD WRITEorSESSION CHARACTERISTICS. - Read detection used
strings.HasPrefixagainstSELECT,WITH,TABLEandVALUES, so anything not recognized as a read (including a read behind a leading comment) was sent down the Exec path. - That path called
tx.Exec(ctx, sqlQuery)with no bind parameters, so pgx used the PostgreSQL simple query protocol, which accepts several semicolon-separated statements in one message. - Session state persisted on pooled connections, so a
RESET ALLorDISCARD ALLthat cleareddefault_transaction_read_onlyon one call left the connection writable by default for later calls.
The flaw affected deployments relying on read_only as a safety boundary and could compromise integrity and availability. Confidentiality was unaffected, since a read-only connection already permits reads.
What you should do
Upgrade to version 1.1.0 or later immediately. After upgrading, review your database audit logs for unexpected DDL or DML issued through the MCP connection. Upgrading prevents further writes but does not tell you whether any occurred.
As a workaround, you can grant the connecting role no write privileges. This is effective, since every route to a write goes through the database’s own permission check, but it removes any legitimate write capability along with the bypass.
What it means
In version 1.1.0, on a read-only connection every query_database statement now uses the extended query protocol, which carries one statement per message, so a multi-statement request is rejected before execution. The guard now inspects the statement with comments removed and literals blanked, and rejects read-write transaction modes, session characteristics, RESET ALL, DISCARD, transaction control and role changes.
Every tool sets the read-only access mode on BEGIN, and the session default is re-applied whenever a connection is returned to the pool, with the connection discarded if that fails.
The advisory notes that connections configured with allow_writes: true keep the previous behaviour, including support for multi-statement scripts, since there is no boundary left to protect in that configuration.



