CVE-2026-125322: pgEdge Postgres MCP Server SQL injection in count_rows where parameter

A SQL injection flaw in pgEdge Postgres MCP Server's count_rows tool allowed callers to extract data from any table the connected database role could read, using subqueries as an inference oracle.

Christopher Ort
By Christopher Ort · 3 min read
Share
A developer reviewing SQL query logs on a laptop screen in a dimly lit office, with PostgreSQL database diagrams visible on a second monitor
Image: AI-generated, i10X
On this page
  1. Quick Take
  2. In plain English
  3. What happened
  4. What you should do
  5. What it means
  6. Sources
i10X Quick Take

Quick Take

  1. What: SQL injection in the count_rows tool’s where parameter allowed subqueries against unintended tables
  2. Who is affected: pgEdge Postgres MCP Server 1.0.0 and earlier, including all alpha and beta pre-releases
  3. What to do: Upgrade to version 1.1.0 or later
  4. Scope: Attackers could read any table the connected database role had SELECT privileges on, but could not write or escalate privileges
  5. Workaround: Grant the connecting role SELECT only on tables you intend to expose

In plain English

The pgEdge Postgres MCP Server is a tool that lets AI assistants query PostgreSQL databases through the Model Context Protocol. A security flaw in its count_rows feature let someone ask how many rows matched a condition, but they could sneak in a hidden query about a completely different table. By checking whether the count was zero or not, an attacker could extract data from any table the database user could read, one character at a time. The flaw is fixed in version 1.1.0. If you use this tool, upgrade now. If you don’t use pgEdge Postgres MCP Server, you can ignore this.

What happened

The count_rows tool in pgEdge Postgres MCP Server accepted a where parameter to filter rows. This parameter was inserted directly into a SQL SELECT COUNT(*) statement with no validation beyond a generic read-only check. According to the security advisory, a caller could supply a subquery in the where clause referencing a table that was never named in the tool call.

For example, calling count_rows(table="orders", where=(SELECT count(*) FROM customers WHERE email = 'guess') = 1) would return the full orders count when the guess was correct and zero when it was wrong. This let an attacker enumerate arbitrary data in a table they never named, using the returned count as a true/false signal.

The advisory states that both boolean-blind and error-based blind injection techniques were confirmed exploitable. The flaw was reproduced directly against the tool’s handler and verified against a live PostgreSQL 16 instance.

The database privilege boundary remained intact. The advisory confirms that attempts to read tables the connected role had no grant on failed with “permission denied for table” errors, and the flaw could not write data or escalate beyond the connected role’s existing SELECT privileges. Classic stacked-query injection (e.g., ; DROP TABLE ...) was already correctly rejected by existing guards.

What you should do

Upgrade to pgEdge Postgres MCP Server version 1.1.0 or later. The fix rejects any where clause containing a bare SELECT or TABLE keyword in the comment-stripped, literal-blanked residue. According to the commit message, the fix was verified by reproducing every payload from the report against a live server before the change and confirming all were rejected afterwards.

As a defense-in-depth measure, grant the connecting database role SELECT privileges only on the tables you intend to expose through the MCP server. This limits what an attacker could reach even if a similar flaw were discovered in the future.

What it means

This vulnerability is a reminder that AI agent tools that construct SQL queries from user input must validate those inputs carefully. Even when a tool appears to accept only a filter predicate, any string interpolation into SQL can become an injection vector if subqueries or other SQL constructs are not explicitly blocked.

The pgEdge team’s fix takes a surgical approach, rejecting subqueries while leaving legitimate simple predicates untouched. The query_database and execute_explain tools were unaffected, since running arbitrary SQL is their documented purpose.

The CVSS score of 6.5 reflects the fact that an attacker needed valid credentials (Privileges Required: Low) and could only read data the connected role already had access to (Confidentiality: High, Integrity: None, Availability: None, Scope: Unchanged).

Sources

Christopher Ort

Christopher Ort

Christopher Ort handles SEO, AI agent workflows and PR & partnerships at i10x.ai, the all-in-one AI workspace built by i10X Global Pte. Ltd. in Singapore. He is a graduate of Friedrich-Alexander-Universität Erlangen-Nürnberg (FAU). He is the author of “The Style Penalty”, a study published on SSRN that analyses 1,576 evaluation decisions by four frontier AI models to show how AI-written CVs fare in automated hiring screens; the research has been covered by heise online and t3n.

Editor's picks

  1. CVE-2026-126776: SiYuan MCP Tools Path Traversal Lets Attackers Write Files Outside Import Directory on Windows
  2. CVE-2026-126658: ByteStash API keys bypass account deactivation in versions before 1.6.2
  3. CVE-2026-125322: pgEdge Postgres MCP Server SQL injection in count_rows where parameter
  4. CVE-2026-68905: Hugo Blog AI Proxy Exposes API Keys Without Authentication
  5. CVE-2026-125321: pgEdge Postgres MCP Server login rate limiting bypassed via X-Forwarded-For