Severity Daily

IT and AI security incidents, checked against the primary source

Tag: CVE-2026-85787

  • Two Postgres MCP servers lost read-only mode the same day: AWS shipped a longer denylist, Postgres MCP Pro has no fix

    Two Postgres MCP servers lost read-only mode the same day: AWS shipped a longer denylist, Postgres MCP Pro has no fix

    Two Postgres MCP servers had their read-only guardrail defeated in records published hours apart on September 4, 2026. AWS fixed its version by adding entries to a denylist. The other project has not shipped a release since May 2025.

    What happened

    On Friday, September 4, 2026, two CVE records landed against Model Context Protocol servers that connect a large language model to a PostgreSQL database. Both describe the same failure: the server’s “read-only” or “restricted” mode did not hold, and a query meant to be confined to reading rows reached past the database instead.

    The first, CVE-2026-85620, was published by VulnCheck at 10:17 a.m. Central and covers Postgres MCP Pro, the crystaldba/postgres-mcp project, at version 0.3.0. NVD’s record states that the server “contains a restricted-mode bypass vulnerability where function-name validation is not applied to RangeFunction nodes in FROM clauses,” and that an attacker “can execute file-reading functions like pg_read_file through FROM-clause syntax to read arbitrary files despite restricted-mode protections.” VulnCheck scores it 9.2 on CVSS 4.0; the CVSS 3.1 base score carried as primary in NVD is 8.6. The weakness is classified CWE-863, incorrect authorization.

    The public GitHub issue the record cites, issue #178, is more specific than the CVE text. It was opened on June 6, 2026 by the researcher VulnCheck credits, George Chen, and it explains that the project’s SafeSqlDriver applies its function allowlist to FuncCall nodes, while a function invoked in a FROM clause parses as a RangeFunction node and never reaches the check. The demonstration needs no extra privilege: SELECT pg_read_file('/etc/passwd') is blocked, and SELECT * FROM pg_read_file('/etc/passwd') returns the file. As of this writing the issue is still open, with no maintainer reply, no fix commit, and no release referenced. VulnCheck’s advisory page states no remediation.

    There is no fixed version to name, and the package registry confirms why. The latest release of postgres-mcp on PyPI is 0.3.0, uploaded May 16, 2025 — the affected version is the current one.

    The second record, CVE-2026-85787, was published by Amazon’s own CNA at 4:17 p.m. Central and covers awslabs.postgres-mcp-server before version 1.1.7. AWS security bulletin 2026-101, timestamped September 4, 2026, 1:00 p.m. PDT, describes “an incomplete list of disallowed inputs in the SQL validation component in Amazon awslabs postgres-mcp-server before version 1.1.7” that “might allow an unauthenticated actor to modify data beyond the read-only scope by placing crafted SQL into the content that is submitted when an authenticated user interacts with the MCP server.” AWS scores it 7.1 on CVSS 4.0 and 6.5 on CVSS 3.1, and classifies it CWE-184 — incomplete list of disallowed inputs.

    That last phrase is the whole design, stated by the vendor. Diffing the 1.1.6 and 1.1.7 wheels from PyPI shows exactly two files changed: a version string, and mutable_sql_detector.py. The fix is a longer list. Version 1.1.7 adds SET_CONFIG to the mutating-keyword set, because, as the shipped comment explains, set_config() “is the function form of SET and mutates session state the same way, but the SET keyword above does not match it (‘set’ is not on a word boundary in ‘set_config’).” It adds a dedicated pattern so that set_config cannot turn off row_security or session_replication_role even when the server is running with writes enabled. It adds a normalization pass so that a double-quoted spelling such as "pg_sleep"(1) is folded to its bare form before the pattern runs — 1.1.6’s own comment had conceded that quoted identifiers “are NOT matched — this is a known limitation of regex-based detection.”

    And it adds nine dblink functions to the dangerous-function set, with a comment stating the stakes plainly: they “open outbound TCP connections from the database backend to an arbitrary host:port. This is a Server-Side Request Forgery primitive: a read query can reach the instance metadata service (169.254.169.254) to steal IAM credentials, probe or connect to internal VPC services, or exfiltrate query results to an attacker-controlled host.” The extension ships in Aurora and RDS shared_preload_libraries.

    The dates do not line up with the advisory. Version 1.1.7 was uploaded to PyPI on June 25, 2026; the bulletin and the CVE record appeared on September 4, 71 days later. In the interim the project shipped 1.1.8, 1.1.9, and, on August 26, 1.2.0, which is current. AWS’s resolution text says “This issue has been addressed in version 1.1.7. We recommend upgrading to the latest version and ensuring any forked or derivative code is patched to incorporate the new fixes.”

    Why it matters

    Read-only mode is the load-bearing assumption in every deployment where a model is handed a database. It is what lets a team connect an agent to production and call the worst case a slow query. Both of these records say that assumption was enforced by inspecting SQL text or its parse tree and rejecting what looked dangerous — and that in both cases something got through.

    What makes the pair worth reading together is that they are not the same implementation mistake. Postgres MCP Pro does the more rigorous thing: it parses the statement and walks the tree. Its bypass is a node type the walker did not visit. AWS does the cheaper thing: it matches patterns against normalized SQL text. Its bypass is a name the patterns did not cover. One failed by omission in an AST traversal, the other by omission in a list — and the fix in both cases is to enumerate more of what an attacker might write. That is the structure of a denylist, and the CWE AWS assigned to its own record names it.

    The distinction between the two servers is not the quality of the guardrail. It is whether anyone is maintaining it. AWS’s list got longer within weeks of a report. Postgres MCP Pro’s report has been public since June 6 with no maintainer response, and the registry says the package has not been touched since May 2025. Anyone who pinned it and moved on is running the vulnerable version by default, and there is nothing to upgrade to.

    The AWS description also names a delivery path that is easy to skim past. The actor is “unauthenticated,” but the SQL arrives “in the content that is submitted when an authenticated user interacts with the MCP server.” That is the indirect-injection shape: the attacker does not talk to the server, they write into something the model reads — a support ticket, a row the agent summarizes, a document in a retrieval index — and the model composes the query. The database sees a well-formed request from a trusted session.

    Which is why AWS’s secondary advice is the durable part of its bulletin: run the server “as a minimal-privilege Postgres role,” not as a superuser or master account, granting only what the workload needs. A denylist decides what a query may say. A role grant decides what the database will do about it, and it does not need to have anticipated dblink_connect_u in advance.

    These two were not alone on Friday. The same VulnCheck batch published CVE-2026-85606 against firecrawl-mcp-server, an arbitrary local file read scored 7.5, and CVE-2026-85661 against excel-mcp-server 0.1.8, scored 9.8, for failing to enforce path confinement in stdio mode when EXCEL_FILES_PATH is unset. The constraint an MCP server advertises is enforced by a check written by hand, and the checks are being read carefully for the first time.

    What to do

    awslabs.postgres-mcp-server: upgrade. Anything below 1.1.7 is affected; 1.2.0, released August 26, 2026, is current and is what AWS means by “the latest version.” If you vendored or forked the server, AWS explicitly asks that you carry the patch across — the changed file is awslabs/postgres_mcp_server/mutable_sql_detector.py.

    Postgres MCP Pro (crystaldba/postgres-mcp): there is no fix. 0.3.0 is both the affected and the newest release. If you run it in restricted mode against anything you care about, treat restricted mode as advisory only until issue #178 is closed, and constrain the database role instead.

    For any database MCP server: connect it as a Postgres role that cannot do what you are trying to prevent. Revoke pg_read_server_files and pg_execute_server_program membership, drop the dblink extension where it is not needed, and grant read on the specific schemas the agent needs rather than connecting as the owner. If an agent’s queries are composed from content outside parties can write, assume the SQL is attacker-influenced and size the role accordingly.

    Sourcing note

    Both CVE records were read from the NVD API at services.nvd.nist.gov, which supplied descriptions, CVSS vectors, CWE assignments, references, and publication timestamps for CVE-2026-85620 (published 10:17 a.m. Central on September 4) and CVE-2026-85787 (published 4:17 p.m. Central the same day). The AWS bulletin was read directly at aws.amazon.com/security/security-bulletins/2026-101-aws/. The VulnCheck advisory and GitHub issue #178 were read at their own URLs. Release dates and the absence of any release after 0.3.0 were taken from the PyPI JSON API, a package registry rather than a report about one. The description of the 1.1.7 change is not from a changelog: the 1.1.6 and 1.1.7 wheels were downloaded from PyPI and diffed, and the quoted comments are the text shipped inside the package.

    Unresolved: the crystaldba project has not responded publicly to issue #178, so we cannot say whether a fix exists unreleased on a branch — GitHub’s releases API returned 403 to automated retrieval, and the absence of a newer PyPI release is what the no-fix statement rests on. AWS does not explain the 71 days between the 1.1.7 upload and the September 4 bulletin. Neither record carries a CISA KEV entry or a federal remediation deadline, and no exploitation of either issue has been reported by any party we checked.