genai
SECURITY LAB
IncidentsAgent abuse

Supabase MCP: A Support Ticket Made Cursor Leak the Integration Tokens Table

High severityResearchJuly 2025LLM01: Prompt InjectionLLM03: Excessive AgencyLLM02: Sensitive Information Disclosure
Status: Research demonstration on dummy data; Supabase recommends read-only, project-scoped mode, wraps query results in warnings, and said in September 2025 that no customer had reported a leak via MCP
Sources checked October 2026
On this page

Nobody broke a permission. The assistant used the developer's own access to do what a customer's ticket told it to.

WhenJuly 2025
TargetSupabase MCP server, used from Cursor under service_role
ResearchersGeneral Analysis (Rez Havaei, Rex Liu, Maximilian Li)
TechniqueIndirect prompt injection in a support ticket; the lethal trifecta in one MCP server
ResultPrivate integration_tokens table copied into the attacker's ticket (demo data)
StatusResearch demo; Supabase recommends read-only, project-scoped mode
Attack flow
  1. 1An anonymous customer files a support ticket with instructions written for the developer's AI assistant
  2. 2The developer asks Cursor for the latest open ticket; the assistant reads it through the Supabase MCP server under service_role
  3. 3It reads the private integration_tokens table and inserts the rows into the ticket thread

What happened

In July 2025, researchers at General Analysis showed how a developer's coding assistant could be turned against the developer's own database. The setup was a demo customer-support app on a fresh Supabase project, filled with dummy data and with row-level security (RLS) switched on. A developer used Cursor with the Supabase MCP server, which lets the assistant run SQL against the project. An anonymous customer filed a support ticket containing instructions written for that assistant. When the developer later asked Cursor to show the latest open ticket, the assistant read the private integration_tokens table and posted its contents back into the ticket thread, where the customer could read them. This was a research demonstration on test data. In September 2025, Supabase said no customer had reported a data leak through MCP.

How the attack worked

The app kept tickets in support_tickets, the conversation on each ticket in support_messages, and provider secrets in integration_tokens. Customers wrote through a public form under the restricted anon role. Support staff used a role limited to the support tables, so when a human agent opened the attacker's ticket and replied, nothing leaked.

The developer's session was different. Cursor's queries ran under service_role, a role that bypasses RLS by design. Asked for the latest open ticket, the assistant loaded the schema, listed tickets, filtered for open ones and fetched the messages on the newest. One of those messages was the attacker's. The assistant treated its embedded instructions as part of the task and issued two more queries: one to read every row of the tokens table, and one to insert the result as a new message on the same ticket. In Cursor these looked like routine tool calls unless the developer expanded them. The attacker refreshed the ticket page and read the secrets.

One server, the whole trifectaSimon Willison pointed out that this single MCP server supplied all three parts of what he calls the lethal trifecta: access to private data, exposure to text an attacker controls, and a way to send data back out, here an ordinary database write.

Root cause

No permission was broken. Every query ran with privileges the developer had granted. The flaw was that text from the least trusted party in the system, an anonymous customer, reached a model running under the most privileged role in the app, and nothing kept the two apart. The tool that read the ticket could also write to it, so the channel that delivered the instructions also carried the data back. RLS could not help, because the assistant's role was built to skip it.

What a test would have caught

One planted ticket would have found it. Write a customer message that asks the assistant to read a table the request does not need, have a developer ask a routine question about tickets, and watch two things: whether the assistant queries a table outside the task, and whether any value from a private table is written somewhere a customer can read. Either result fails the test; the second is the leak itself.

How to prevent it

  • Keep privileged roles and production data away from agents. In its September 2025 response, Supabase told developers to keep agents off production data and to give them development or anonymised data instead.
  • Run read-only and project-scoped. Read-only mode blocks the write that carried the tokens back. General Analysis warns that data read this way can still leave through other tools or outputs, so check those paths too.
  • Keep manual approval on. A request to view a ticket gives no reason to query a tokens table, and a reviewer who expands the call can see that.
  • Track where values came from. Data read from a private table should never reach a sink the public can read, whatever the instructions say. Supabase's server now wraps query results in a warning not to follow embedded commands, and its own documentation says that is not a complete defence.

Feel it yourselfThe replay lab gives you a support triage agent with a public ticket queue, a sealed private account store and a public reply channel. See whether a ticket you write can carry a private value all the way to the customer.

FAQ

What was the Supabase MCP data leak?

A July 2025 research demonstration by General Analysis. A support ticket written by an anonymous customer carried instructions for a developer's Cursor assistant. When the developer asked Cursor to show the latest open ticket, the assistant, connected through the Supabase MCP server and running queries under service_role, read a private table of integration tokens and posted it into the ticket thread. It ran on dummy data, and in September 2025 Supabase said no customer had reported a leak through MCP.

Why didn't row-level security stop it?

The assistant's queries ran under service_role, which bypasses row-level security by design, so every query it ran was allowed. The flaw was that it took instructions from ticket text, acted on them with the developer's privileges, and wrote the result to a table the attacker could read.

How do you use a database MCP server safely?

Keep agents off production data, run the server read-only and scoped to one project, leave manual approval of tool calls on, and enable only the tool groups the task needs. Treat every value read from user-submitted rows as untrusted, and stop private data from flowing into anything a customer can see.

Replay this attack
Plant a customer ticket in front of a support triage agent and see whether it can steer a sealed private account read into the agent's public reply, the same public-intake, private-read, public-write flow General Analysis ran through Cursor and the Supabase MCP server.
Open the live lab
A live, sandboxed lab. It recreates the technique, not this exact product.