system: OPERATIONAL
← back to all hacks
AGENTS CRITICAL NEW

mcp-pinot: an unauthenticated MCP server as a confused deputy

A June 2026 disclosure shows an Apache Pinot MCP server that bound to 0.0.0.0 with OAuth off, letting any network-adjacent caller run its privileged database tools.

2026-07-04 // 6 min affects: mcp-pinot, model-context-protocol, apache-pinot

What is this?

On 18 June 2026, a critical vulnerability was published in mcp-pinot, an open-source Model Context Protocol (MCP) server that lets an LLM agent query and manage an Apache Pinot real-time analytics cluster. In version 3.0.1 and earlier, the server started an HTTP MCP endpoint bound to 0.0.0.0:8080 with authentication disabled by default. Any caller that could reach that port — a machine on the same network, a container neighbour, or anything behind a misconfigured firewall — could invoke every tool the server exposed, without logging in.

The maintainers (StarTree) fixed the issue in version 3.1.0, released 25 May 2026, ahead of public disclosure. The flaw is rated 10.0 (Critical) and is a textbook instance of a confused deputy: the server, not the attacker, holds the credentials that do the damage.

How it works

This is a configuration and design flaw, not a memory-corruption exploit, so the mechanism is easy to state without a weaponised payload.

The mcp-pinot server connects to its Pinot cluster using a server-side service account loaded from environment variables (a token, or a username and password). Those credentials are usually privileged, because the server needs to read tables, list schemas, and sometimes write configuration. When an MCP client calls a tool such as read_query, the server forwards that call to Pinot using its own credentials.

In the vulnerable default, there was no gate in front of that forwarding. The HTTP listener answered on every interface (0.0.0.0) rather than loopback (127.0.0.1), and OAuth was off. An unauthenticated request could therefore reach the tool layer directly and ride the server’s identity into the database. The exposed tools covered the full surface of the cluster: read_query runs arbitrary SELECT statements, list_tables and the various metadata tools enumerate schemas and configuration, and create_schema, update_schema, and update_table_config mutate the cluster where the service account has write rights. One tool, reload_table_filters, even echoed the previous and new server-side filter lists back to the caller — leaking the very allowlist meant to constrain queries.

The scope is what makes this a confused deputy rather than a simple exposed endpoint: the vulnerable MCP component sits on one security boundary, but its credentials act on a separate one (the Pinot cluster). The attacker never needs to know the database password; the deputy spends it on their behalf.

Why it matters

MCP servers are becoming the standard glue between agents and real systems, and each one is a small proxy that holds credentials for something valuable. That makes their default network posture a security decision, not a convenience setting. Binding to 0.0.0.0 “so it works from another machine” quietly converts a local developer tool into a network service — and if that service front-runs a privileged database account with no authentication, the blast radius is the whole backend.

This is not an isolated slip. The same shape — an AI-adjacent HTTP server listening on all interfaces with authentication off by default — produced a separate critical remote-code-execution finding in the MCPJam MCP inspector earlier in 2026, and it echoes the “lethal trifecta” pattern where a system combines privileged access, untrusted input, and an exfiltration path. National guidance has caught up: recent NSA and allied-agency design considerations for MCP stress authentication, server trust, and transport controls precisely because these proxies keep shipping open. The takeaway for anyone deploying an MCP server is that the server’s default configuration is part of your attack surface, even before an agent does anything clever.

Defenses

Bind to loopback by default. A development or single-host MCP server should listen on 127.0.0.1, never 0.0.0.0, unless remote exposure is an explicit, reviewed choice. For mcp-pinot specifically, set MCP_HOST=127.0.0.1 if you cannot yet upgrade.

Never expose an unauthenticated tool server on the network. If remote access is genuinely required, require authentication first. mcp-pinot 3.1.0 refuses non-loopback HTTP/HTTPS unless OAuth is enabled; enable it (OAUTH_ENABLED=true) and put the endpoint behind a VPN or SSH tunnel rather than the open internet.

Give the server the least privilege it needs. Treat the service account behind an MCP server as internet-facing. Scope its database rights to read-only where possible, restrict it to the specific tables the agent needs, and separate read and write duties so a read tool cannot silently gain write power.

Constrain the tools, not just the network. Server-side query validation matters even with auth on. The 3.1.0 fix added parser-backed, single-statement, read-only validation for read_query, so a “read” tool cannot be coerced into multi-statement or write behaviour. Apply the same rigour to any tool that accepts free-form input.

Make exposure opt-in in your deployment tooling. The patched release also made its Helm exposure opt-in and OAuth-gated. Default your Kubernetes and container manifests to closed, so a copy-pasted chart does not publish a credentialed proxy by accident.

Status

ItemReferenceDateNotes
AdvisoryGHSA-73cv-556c-w3g6 / CVE-2026-4925718 Jun 2026Missing authentication for critical function (CWE-306); CVSS 3.1 = 10.0 (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
Affectedmcp-pinot < 3.1.0HTTP MCP server default-bound to 0.0.0.0:8080, OAuth disabled by default
Fixedv3.1.025 May 2026Default bind 127.0.0.1; non-loopback refused without OAuth; Helm exposure opt-in and OAuth-gated; read-only single-statement validation for read_query
Root causeConfused deputyServer-side Pinot service-account credentials used to serve unauthenticated callers

The practical lesson is narrow and portable: an MCP server is a credentialed proxy, and its default listening address and auth posture are security controls. Check every MCP server you run for where it binds and whether it authenticates before it forwards a tool call — because the credentials it lends out are yours.

Sources