Home / The Canary Check

The Canary Check #004: Your AI agent's Supabase token is too powerful

2026-10-15 · One finding, one fix, before you ship.

Finding: an all-access token wired into your AI editor

If you connected Cursor, Claude Code or a CI job to Supabase with an account-level personal access token, that token can do whatever you can, across every project you can reach. As of October 6, 2026, Supabase's scoped personal access tokens are generally available: you can limit a token to selected projects, pick read or read-write per capability (projects, database, auth, storage), and set an expiry of up to one year. SQL runs read-only unless the token has Database read-write, and revealing secret API keys needs its own permission.

Fix: replace it, don't edit it. You can't change a token's access after it's created, so create a new scoped token for one project with only the permissions its tools need, update your MCP or CI config, then delete the old one. Existing tokens keep working until they expire or you delete them, so nothing forces this for you.

For day-to-day MCP use, Supabase's docs recommend scoping the server to one project and turning on read-only mode:

https://mcp.supabase.com/mcp?project_ref=<your-ref>&read_only=true

Check: in the dashboard, open the token's detail view. It lists the MCP tools the token can call. Anything you don't recognise is too much.

Guide: https://prodcanary.com/guides/supabase-mcp-server-security-cursor/ Sources: https://supabase.com/changelog/scoped-personal-access-tokens-ga · https://supabase.com/docs/guides/getting-started/mcp

News

UpGuard Research published the largest study yet of exposed Supabase apps on September 24, 2026. From about 300,000 domains showing signs of Supabase, it found 16,326 databases exposing readable tables, and over half had indicators of personal data. It notes that tables created programmatically through the API, which is how coding agents work, don't get RLS by default. What to do: list your tables that still have RLS off (query in the tip below). (https://www.upguard.com/blog/everything-everywhere-systemic-data-exposure-in-supabase-apps)

Tip

Run this in the SQL Editor after every AI-generated migration:

select tablename from pg_tables
where schemaname = 'public' and rowsecurity = false;

An empty result is what you want. (https://supabase.com/docs/guides/database/postgres/row-level-security)

Free scan, no signup: https://prodcanary.com/#scan

Get the next one

A 3-minute security note for people shipping with Lovable, Bolt, Cursor, Supabase and Firebase, on weekday mornings.

Subscribe free