{"slug": "is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t", "title": "Is your Supabase anon key safe in the frontend? Yes. Here's what isn't.", "summary": "A developer built LeakPatrol, a free read-only security scanner that checks AI-generated Supabase apps for leaked service_role keys, publicly exposed .env files, missing security headers, and tables readable without authentication. The tool's writeup argues the Supabase anon key is safe to ship in frontend JavaScript because access is governed by Row Level Security, while the service_role key bypasses RLS entirely and leaks everything if bundled via VITE_, NEXT_PUBLIC_ or REACT_APP_ variables. It also flags permissive using (true) policies, public storage buckets, and SECURITY DEFINER views as common leak vectors in apps built with Lovable, Bolt, v0 or Cursor.", "body_md": "If you've built an app with Lovable, Bolt, v0 or Cursor on top of Supabase, you've probably opened DevTools, seen a long `eyJ...` key in your JavaScript, and felt your stomach drop.\n\nGood news first: **that key is supposed to be there.** Here's what it actually does, and the four things that *do* leak data in AI-built Supabase apps.\n\nSupabase gives every project two kinds of key:\n\n| Key | Starts with | Where it belongs | \n|---|---|---|\n| anon / publishable | `eyJ...` (role`anon` ) or`sb_publishable_` | The browser. Fine to ship. | \n| service_role / secret | `eyJ...` (role`service_role` ) or`sb_secret_` | Only on a server. Never in the browser. | \n\nThe anon key just identifies your project. On its own it grants nothing: what someone can do with it is decided entirely by your **Row Level Security (RLS)** policies.\n\nThat's also the catch. **The anon key is safe only if RLS is doing its job.**\n\nWith RLS off, anyone who copies your anon key out of your JavaScript can read, and often write, the whole table with a single request. No login needed.\n\nCheck every table in the SQL editor:\n\n```\nselect tablename, rowsecurity\nfrom pg_tables\nwhere schemaname = 'public';\n```\n\nAnything showing `false` is open. Turn it on and add a policy that ties rows to their owner:\n\n```\nalter table public.profiles enable row level security;\n\ncreate policy \"Users read their own profile\"\non public.profiles for select\nusing (auth.uid() = user_id);\n```\n\nWatch out for policies with `using (true)`. They turn RLS on but let everyone through, which AI tools sometimes generate to \"fix\" a permissions error.\n\nThe service_role (or `sb_secret_`) key **bypasses RLS completely**. If it's in your frontend, every table is open no matter how good your policies are.\n\nAI tools usually put it there by accident: a `VITE_SUPABASE_SERVICE_ROLE_KEY` or `NEXT_PUBLIC_...` variable, added to make an admin feature work. **Anything prefixed `VITE_`, `NEXT_PUBLIC_` or `REACT_APP_` is bundled into the JavaScript every visitor downloads.**\n\nIf you find it: rotate the key in Supabase (Settings → API) right away, then move the admin work into an Edge Function that reads the key from Supabase secrets.\n\nStorage has its own policies, separate from your table RLS, and they're easy to forget. A \"public\" bucket means anyone with a file's URL can download it. Fine for avatars, not for invoices, ID photos or exports.\n\nIn Storage, check which buckets are public, and give private ones policies on `storage.objects`, just like tables.\n\nTwo quieter ones:\n\n`with (security_invoker = on)`.` SECURITY DEFINER``service_role`, `sb_secret_`, `sk-` and `sk_live`. You should find none.` true`.` using (true)` in your policies.\nIf you'd rather not do it by hand, I built [LeakPatrol](https://www.getleakpatrol.com/?ref=devto), a free read-only check that looks for leaked keys, a public `.env` and missing security headers, and, once you prove you own the site, which Supabase tables can be read without logging in. Each finding comes with a prompt you can paste back into your AI tool to fix it.\n\nThe anon key was never the problem. What you've built around it is what counts.", "url": "https://wpnews.pro/news/is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t", "canonical_source": "https://dev.to/leakpatrol/is-your-supabase-anon-key-safe-in-the-frontend-yes-heres-what-isnt-5919", "published_at": "2026-10-18 13:36:43+00:00", "updated_at": "2026-10-18 13:47:08.628990+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools", "ai-products"], "entities": ["Supabase", "LeakPatrol", "Lovable", "Bolt", "v0", "Cursor"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t", "markdown": "https://wpnews.pro/news/is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t.md", "text": "https://wpnews.pro/news/is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t.txt", "jsonld": "https://wpnews.pro/news/is-your-supabase-anon-key-safe-in-the-frontend-yes-here-s-what-isn-t.jsonld"}}