Skip to content

Our research

CVE-2026-110787: How the pREST MCP Endpoint Bypassed the expose Settings

By Lucas Weber, CyberSec42 · Updated 28 Oct 2026

Schematic of an MCP server sitting between an AI client and a target system

CVE-2026-110787 is an access control weakness (CWE-284) in the open source project pREST: the MCP endpoint /_mcp ignored the [expose] settings and listed databases, schemas, tables and column names even when the operator had switched those listings off. GitHub advisory GHSA-x62p-38px-pp73 rates it CVSS 5.3 (medium) and lists the Go module github.com/prest/prest/v2 up to and including version 2.4.0 as affected; the fix shipped in 2.4.1 on 29 July 2026. Only deployments that actively used [expose] to hide their catalog were affected, and what leaked were names, not table contents beyond what the access rules already allowed.

In short.

Background

What pREST is and what [expose] controls.

Go to section

The vulnerability

The mechanism in plain words and in detail.

Go to section

Who was affected

Versions and configurations.

Go to section

The fix

What changed and what operators should do.

Go to section

Timeline

Publicly documented dates only.

Go to section

The underlying pattern

A new MCP surface next to an old control.

Go to section

Key facts

ItemDetail
IdentifiersCVE-2026-110787 (assigned), GHSA-x62p-38px-pp73
ProductpREST (prest/prest), Go module github.com/prest/prest/v2
ClassAccess control bypass; CWE-284 “Improper Access Control”
SeverityCVSS 3.1: 5.3, medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N); 4.3 with authentication enabled according to the advisory (PR:L)
Affectedall versions up to and including 2.4.0
Fixed2.4.1, released 29 July 2026
PublishedGitHub advisory on 29 July 2026; the CVE record was not yet published in the CVE List as of 28 October 2026
CreditReported by CyberSec42 (GitHub: lwebmedia)

Background: what pREST is and what [expose] controls

pREST is an open source project written in Go and released under the MIT licence. It puts a REST API in front of an existing PostgreSQL database, and since version 2.5 also MySQL, without any backend code of your own: reads, writes, filtering, custom SQL routes, authentication and access rules. Since version 2.1.0, released on 9 July 2026, the same server also offers a Model Context Protocol (MCP) endpoint at /_mcp. AI agents can use it to explore the database catalog, describe tables and read rows. The documentation describes the endpoint as read-only by design and says it shares the authentication and access rules of the REST API.

Two configuration sections matter here, and pREST deliberately keeps them apart:

Both sections are open by default: expose.enabled is false, so everything can be listed, and access.restrict is false as well. Authentication (auth.enabled) is also off in the default configuration. Anyone running pREST in public therefore switches these layers on deliberately. For the general picture of hardening MCP servers, see our guide to securing MCP servers; this article covers the specific case.

The vulnerability

In plain words

Picture an office building that has taken down the tenant directory in its lobby so visitors cannot see which companies are inside. Who may enter which office is still decided by the access card; the directory has nothing to do with that. Then the building opens a second entrance, and the full directory is still hanging on the wall there, floor plan included.

That is how pREST behaved up to version 2.4.0. The removed directory is the [expose] setting for the REST routes, the second entrance is /_mcp, and the access card is [access].

In detail

pREST enforces [expose] in exactly one place, the ExposureMiddleware. It joins the global middleware stack whenever expose.enabled is on and compares each request path against three fixed prefixes: /databases, /schemas and /tables. If a prefix matches and the corresponding setting is false, the server answers with HTTP 401 (“unauthorized listing”). Every other path is passed through unchecked.

/_mcp matches none of those prefixes. The MCP tools prest.list_databases, prest.list_schemas and prest.list_tables returned the same catalog as the REST routes but never consulted the [expose] configuration. On top of that came the discovery response to a plain GET /_mcp: it enumerates the available tools, including one read tool per table whose name carries the database, schema and table and whose description lists the column names. A caller correctly refused at GET /databases therefore saw the full catalog through /_mcp without calling a single tool.

This is important for the assessment: the read tools on /_mcp remained subject to [access]. With access.restrict = true, pREST also filtered the schema and table listings by those rules, though according to the advisory not the database listing. What leaked was metadata, not the contents of tables the caller would not have been allowed to read anyway.

Reading the vector: PR:N reflects the documented default configuration, in which auth.enabled is off and /_mcp requires no login. With authentication enabled, the caller needs a valid account with any privileges; the advisory gives PR:L and a base score of 4.3 for that case. C:L stands for a limited loss of confidentiality, while integrity and availability are not affected. We recalculated both base scores using the formula in the CVSS 3.1 specification.

Schematic flow

Caller asks for the catalog ExposureMiddleware checks three paths GET /databases 401, refused /_mcp returns the catalog works as intended up to 2.4.0 unchecked
Up to 2.4.0 the ExposureMiddleware only checked the three REST paths, and /_mcp passed through unchecked. From 2.4.1 the MCP tools check the [expose] settings too.
  1. The operator sets expose.enabled = true and switches off the database, schema or table listing.
  2. A caller who can reach the pREST HTTP endpoint requests /databases and is correctly refused.
  3. The same caller requests /_mcp. The middleware does not recognise the path as a catalog route and passes the request on.
  4. The discovery response and the listing tools of the MCP endpoint return database, schema, table and column names.
  5. Which table contents the caller can read afterwards is still decided by [access], exactly as for a direct REST request.

We deliberately do not publish exploit code. The description is enough to assess your own installation and to follow the fix.

Who was affected

The advisory lists the Go module github.com/prest/prest/v2 in all versions up to and including 2.4.0 as affected. According to the release notes and the documentation, the /_mcp endpoint has only existed since version 2.1.0; it is not registered in the 2.0.0 source code. In practice the issue only mattered to operators who actually used [expose] to hide their catalog.

ConfigurationAssessment up to 2.4.0
Version before 2.1.0No MCP endpoint, so the path described here does not exist
expose.enabled = false (default)The catalog can be listed via REST and MCP alike, as configured. The vulnerability changes nothing here
expose.enabled = true with listings switched off, authentication offAffected. Anyone who could reach the HTTP endpoint saw the catalog through /_mcp (CVSS 5.3)
expose.enabled = true with listings switched off, authentication onAffected for every logged-in account, regardless of its privileges (CVSS 4.3)
additionally access.restrict = trueSchema and table listings on /_mcp were limited to what the access rules allow the caller; the database listing was not

How much an exposed catalog gives away depends on the names. Tables such as orders say little, schemas named after customers or projects say more. It also depends on who could reach the HTTP endpoint: only the local machine, an internal network or the internet.

The fix and what operators should do now

What the 2.4.1 fix changes

The fix (pull request #1016) defines in one central place what [expose] permits: three predicate functions for database, schema and table listings. The REST middleware and the MCP tools now both consult the same functions. A code comment states the reason explicitly: a new discovery endpoint should no longer be able to escape the control silently.

On /_mcp this means, according to the documentation: if a listing is switched off, the matching prest.list_* tool disappears from the discovery response and a direct call fails with “unauthorized listing”. If any listing is switched off, the discovery response also stops enumerating the per-table read tools, because their names and descriptions would reveal the catalog. The generic tools prest.describe_table and prest.select_table remain available within the limits of [access] for callers who already know their target. The fix adds tests for exactly these cases and extends the comment in the sample configuration to cover the MCP endpoint. The same commit also contains an unrelated hardening of parameter checks for scripts, which is not part of this advisory.

Recommendations for operators

The following steps are our recommendations, not requirements from the project.

StepAction
1. Check your versionUpgrade to 2.4.1 or later. The most recent published release as of 28 October 2026 is 2.5.2.
2. Verify the effectIf you use [expose]: after the upgrade, check on your own installation that the /_mcp discovery response no longer lists table and column names.
3. Protect data with [access]Do not protect sensitive tables by hiding them. Use access.restrict = true with permissions per table, field and user.
4. Turn on authenticationIf pREST is reachable beyond the local network, enable auth.enabled. /_mcp uses the same authentication as the REST routes.
5. Block an unused endpointIf you do not use MCP, you can block /_mcp at the reverse proxy. The advisory names this as an interim measure as well.
6. Review your logsIf your reverse proxy logs requests: look for calls to /_mcp from unexpected sources.

Timeline

Only dates that can be backed by public sources are listed.

DateEventSource
9 Jul 2026Release 2.1.0 introduces the /_mcp endpointGitHub release v2.1.0, documentation
27 Jul 2026Release 2.4.0, the last affected version; according to the advisory, the review covered the source code at this releaseGitHub release v2.4.0, advisory
27 Jul 2026Advisory created in the repositoryGitHub API for the advisory
29 Jul 2026Fix merged (pull request #1016), GHSA-x62p-38px-pp73 published, release 2.4.1GitHub
28 Oct 2026CVE-2026-110787 is recorded in the advisory; the CVE record is not yet published in the CVE ListAdvisory, MITRE CVE API

The fixed version was therefore available two days after the advisory was created. When the CVE number was assigned is not publicly documented, so it is not listed.

The underlying pattern: a new MCP surface bypasses an existing control

CVE-2026-110787 reflects a pattern that is likely to become more common as MCP spreads. A mature product has an access control tied to specific routes. Later, an MCP endpoint is added that serves the same data through a new path. The old control does not know about the new path, and nobody notices, because the old routes still refuse correctly. To the operator, the setting looks effective.

In our explanation of the OWASP MCP Top 10, this maps to class 8, authorization applied unevenly across the protocol surface, with a touch of class 4, a control that promises more than it covers. Developers who add an MCP surface to an existing application can take four rules from it:

For operators, the flip side applies: an MCP endpoint in an existing application is one more interface to your data. Check whether every setting you rely on also takes effect there. More documented findings of this kind are on our research page.

Thanks to the pREST maintainers

We thank the pREST maintainers for the fast and constructive collaboration under coordinated disclosure. The report was submitted confidentially as a security advisory in the repository. Two days after the advisory was created, the fix, tests, updated documentation and release 2.4.1 were out, and the advisory credits CyberSec42 as the reporter. The fix does more than close the reported path: it consolidates [expose] into one central definition that future discovery endpoints can build on.

On our method: we reviewed only the project's public source code. According to the advisory, no running pREST instance, database or third-party system was contacted, all example values in the report are fabricated, and no issues, pull requests, comments or branches were opened or changed on GitHub.

Do your access rules hold on the MCP endpoint too?

We test MCP servers and AI agents within a scope agreed in writing: whether existing controls apply equally on every surface, what discovery responses give away, how authentication and access rules interact and what a tool call can actually reach. Every finding comes with reproducible evidence and a concrete fix. Learn more about AI pentesting & MCP security.

Request an AI pentest

CyberSec42 is an independent technical security assessment, not an accredited certification body, and does not provide legal advice. CyberSec42 is not affiliated with the pREST project.

Frequently asked questions

What is CVE-2026-110787?

An access control weakness in pREST (CWE-284). The MCP endpoint /_mcp listed databases, schemas, tables and column names even though the operator had switched those listings off via [expose]. GitHub advisory GHSA-x62p-38px-pp73 rates it CVSS 5.3 (medium). The CVE number is assigned; the record was not yet published in the CVE List as of 28 October 2026.

Which pREST versions are affected?

According to the advisory, all versions of the Go module github.com/prest/prest/v2 up to and including 2.4.0. The MCP endpoint has existed since 2.1.0. The issue is fixed in 2.4.1, released on 29 July 2026. Upgrade to 2.4.1 or later.

Could attackers read table contents this way?

Not beyond what the access rules already allowed. According to the documentation, [expose] only controls discovery, while data access is governed by [access], and that applied to /_mcp just as it did to the REST routes. What became visible were the names of databases, schemas, tables and columns. If you protected sensitive tables only by hiding them, configure [access].

Am I affected if I do not use [expose]?

No, not in the sense of this vulnerability. With the default expose.enabled = false, the catalog can be listed via REST and MCP alike, as configured. You should still upgrade, since your configuration may change later.

Was the vulnerability actively exploited?

The public sources, meaning the advisory, release notes and documentation, make no statement about it. We only reviewed source code and did not examine any running installations.

Further reading

Sources