[{"data":1,"prerenderedAt":121},["ShallowReactive",2],{"cw20ODrw3B":3,"related-supabase-notes/why-16000-supabase-databases-were-left-exposed":60},{"id":4,"slug":5,"title":6,"excerpt":7,"meta_title":8,"meta_description":9,"page_content":10,"featured_image":51,"fields":52,"tags":54,"published":47,"published_at":57,"created_at":58,"updated_at":59},"fd7b0e56-d3d2-4824-a2ce-2948a6ecfa7d","notes/why-16000-supabase-databases-were-left-exposed","16,326 Supabase Databases Were Left Exposed. Here's Why","UpGuard found over 16,000 public Supabase databases leaking real personal data this week. The cause traces back to one setting, and it's worth checking on your own project.","16,000 Exposed Supabase Databases: What Happened","UpGuard found 16,326 public Supabase databases leaking real data this week. The cause was one setting. Here's what to check on your own project.",{"blocks":11},[12,18,40],{"id":13,"data":14,"type":17},"66238f79-95a4-44ec-8637-2ed41d4f2189",{"content":15,"maxWidth":16},"\u003Cp>On September 25, TechCrunch reported on research from the security firm UpGuard: out of roughly 300,000 Supabase project domains they scanned, 16,326 had at least one table that anyone on the open internet could read. More than half of those held some kind of personal data: names, addresses, phone numbers. A smaller slice exposed password fields directly, or authentication tokens that would let an attacker log in as someone else without ever guessing a password. The examples UpGuard published were mundane in a way that makes the story worse, not better. Thousands of license plates and vehicle details from a US valet parking app. Contact records from an immigration services firm. Data tied to a foreign consulate. None of it needed a clever exploit. It was sitting behind a URL anyone could construct, because nothing was told to stop them.\u003C/p>\n\n\u003Ch2>The one setting that decided all of it\u003C/h2>\n\n\u003Cp>The cause is not a bug in Supabase. It is Row Level Security, RLS for short, and a quirk in how it gets switched on. Create a table from the Supabase dashboard and RLS is enabled by default, with no policy attached, which means nobody can read a row until you write one. Create the exact same table with a SQL migration, the Supabase CLI, or any tool that talks to Postgres directly, and RLS stays off unless you turn it on yourself. That is a sensible default for someone clicking through the dashboard and a dangerous one everywhere else, because almost no real project gets built by clicking through the dashboard. Projects get built with migrations, with ORMs, and increasingly with an agent writing the SQL on your behalf.\u003C/p>\n\n\u003Cp>I build headless projects on \u003Ca href=\"/supabase\">Supabase\u003C/a> for the reasons most developers land there: hosted Postgres you can actually query, a generous free tier, and none of the vendor lock-in that comes with a proprietary CMS. The part nobody spells out clearly enough is that Postgres has no opinion on who can read what until you give it one, and a tool generating your schema for you will happily generate a table with no access control at all if nothing in its instructions tells it to check.\u003C/p>\n\n\u003Ch2>Coding agents did not invent this, they made it faster\u003C/h2>\n\n\u003Cp>UpGuard's own researchers were careful not to pin this entirely on \"vibe coding.\" Blaming Lovable or Replit users alone misses the point. The same pattern shows up in projects built with \u003Ca href=\"/notes/is-claude-ai-good-for-small-business\">Claude Code\u003C/a>, with Codex, and in plenty of hand-written code from developers who have been doing this for a decade. What changed is the workflow. An agent that can provision a table, wire up an API route, and build the frontend that calls it, all in one sitting, removes the moments where a developer used to stop and actually look at what they had just created. Nobody sits down and deliberately decides to skip Row Level Security. It gets skipped because the pause that used to force the question is gone, and the app runs perfectly well without it right up until someone finds the table.\u003C/p>\n\n\u003Cp>This is not a new shape of problem, even if the tooling is new. Magento shipped for years with an admin setup that was permissive until a developer locked it down by hand, and stores are still getting backdoored today by people who never got round to it, most recently through the CVE-2026-75650 zero-day that had Adobe pushing emergency hotfixes and store owners rotating every credential on the box. Different stack, same root cause: a secure default that only holds if somebody actually checks it, on a system built by a team who assumed somebody would.\u003C/p>\n\n\u003Ch2>What to actually check this week\u003C/h2>\n\n\u003Cp>If you have a Supabase project running anywhere, whether you wrote every line yourself, inherited it from someone else, or had most of it generated for you, this is worth an afternoon.\u003C/p>\n\n\u003Cul>\n\u003Cli>List every table in your public schema and confirm RLS is switched on for each one, not only the ones you remember creating by hand in the dashboard.\u003C/li>\n\u003Cli>For every table where RLS is on, read the actual policy. Enabled is not the same as correct. A policy that lets any authenticated user select everything is barely better than having none.\u003C/li>\n\u003Cli>Test access as an anonymous visitor and as a logged-in user who should not have access to a given row, not only as yourself signed in with full admin rights.\u003C/li>\n\u003Cli>Check your views separately. A view created with security definer can quietly bypass the RLS sitting on the tables underneath it, and it is easy to forget views count too.\u003C/li>\n\u003Cli>Search your client-side code and your git history for a service role key. It should never leave the server. If you find one in a frontend bundle, rotate it today, not this week.\u003C/li>\n\u003C/ul>\n\n\u003Cp>None of this takes long for a project of normal size. The expensive part was never the fix. It is finding out you needed one after the data has already been sitting in a search engine's cache, or in a scraper's dataset, for six months. If you inherited a Supabase project you did not build from scratch, or if an agent scaffolded the first version of it for you, this is worth doing even if nothing looks obviously wrong today.\u003C/p>\n\n\u003Cp>Supabase's own CISO told TechCrunch that security is \"a shared responsibility,\" which is true and also exactly what you would expect a vendor to say after a story like this. The defaults on offer are reasonable, and better than most people give them credit for. What gets built on top of them is still yours to get right, whether you typed it or an agent did.\u003C/p>\n\n\u003Cp>This is not the first Supabase story I have flagged in a \u003Ca href=\"/notes/weekly-roundup-2026-09-18\">weekly round-up\u003C/a> this month, and it will not be the last. I have also written about \u003Ca href=\"/notes/building-with-ai-not-vibe-coding\">building with AI without it turning into vibe coding\u003C/a>, and this is exactly the failure mode that piece was warning about. If you want a second pair of eyes on a Supabase project, whatever built it, get in touch and I will go through the schema with you properly rather than skim it for ten minutes and tell you it looks fine.\u003C/p>\n\n\u003Cp>\u003Ca href=\"/contact\">Get in touch\u003C/a>\u003C/p>\n","lg","wysiwyg",{"id":19,"data":20,"type":39},"fa000001-0000-4000-8000-000000000001",{"items":21,"title":37,"subtitle":38},[22,25,28,31,34],{"answer":23,"question":24},"Possibly, if your tables were created with migrations, the CLI, or an agent rather than clicked together in the dashboard. Those routes leave Row Level Security off unless you turn it on. The quickest check is to open each table and confirm RLS is enabled with a policy attached. If you are not sure, it is worth having someone look.","Is my Supabase database at risk from this?",{"answer":26,"question":27},"Row Level Security is the Postgres feature that decides who can read each row. With it off, anyone who can reach your project URL can read the table. The dashboard turns it on by default, but migrations and the CLI leave it off, which is how more than sixteen thousand projects ended up readable by the public.","What is Row Level Security and why did it matter here?",{"answer":29,"question":30},"No. The cause was not a bug in Supabase, it was RLS being left off on tables made outside the dashboard. Built properly, with RLS on and a policy for every table, Supabase is a solid foundation and I use it for exactly that. The danger is treating the default as handled when it is not.","Does this mean Supabase is unsafe to build on?",{"answer":32,"question":33},"That is the riskiest case, because an agent writing SQL creates tables the same way a migration does, with RLS off unless it is told otherwise. If nobody reviewed the security side afterwards, assume it needs checking. An agent is good at writing the table and less reliable at remembering to lock it down.","I used an AI agent to build my database. Should I worry?",{"answer":35,"question":36},"Enable RLS on every table that holds real data, then write a policy for each one saying who can read and write it. Never leave a table with RLS on but no policy and assume that is fine, and never ship a public key against tables you have not checked. If that sounds like work you would rather hand over, I can audit it.","How do I actually lock this down?","Supabase security, answered","Common questions about the RLS exposure and whether your own project is affected.","faq",{"id":41,"data":42,"type":50},"c7000001-0000-4000-8000-000000000001",{"title":43,"subtitle":44,"buttonLink":45,"buttonText":46,"useGradient":47,"secondaryButtonLink":48,"secondaryButtonText":49},"Worried about your own Supabase project?","I build headless sites on Supabase with Row Level Security locked down from the start. If you want yours checked over, let's talk.","/supabase","Why I build on Supabase",true,"/contact","Get your setup checked","cta","",{"author":53},"Adam Jackson",[55,56],"supabase","ai","2026-10-02T08:00:00+00:00","2026-09-27T07:18:05.689274+00:00","2026-10-02T08:00:01.68075+00:00",[61,74,85,96,99,110],{"id":62,"slug":63,"title":64,"excerpt":65,"meta_title":66,"meta_description":67,"featured_image":51,"fields":68,"tags":70,"published":47,"published_at":73,"created_at":73,"updated_at":73},"3fa30c75-b63a-4414-8078-bf9a57b7eb3c","notes/weekly-roundup-2026-10-16","Weekly round-up: Magento APSB26-153 and a Supabase TLS deadline","Adobe's APSB26-153 has five critical Magento fixes, Supabase disables old TLS 1.2 ciphers on 10 November, and the .NET SDK grows up.","Weekly Round-Up: Magento APSB26-153, Supabase TLS","This week: Magento APSB26-153 with five critical fixes, Supabase disabling old TLS 1.2 ciphers on 10 November, and .NET SDK updates.",{"author":69},"Headless Digital",[71,72,55],"roundup","magento","2026-10-16T07:14:57.117895+00:00",{"id":75,"slug":76,"title":77,"excerpt":78,"meta_title":79,"meta_description":80,"featured_image":51,"fields":81,"tags":82,"published":47,"published_at":84,"created_at":84,"updated_at":84},"cdfe1566-04cc-4260-96ab-1f2d0bf327d7","notes/weekly-roundup-2026-10-09","Weekly round-up: Nuxt 4.6, scoped Supabase tokens, and a December deadline","Nuxt 4.6 and the end of Nuxt 3, scoped Supabase personal access tokens, the 1 December adapter removal, and WordPress 7.1.3.","Weekly Round-Up: Nuxt 4.6, Supabase Scoped Tokens","This week: Nuxt 4.6 and Nuxt 3 end of life, scoped Supabase access tokens, a 1 December deprecation date, and WordPress 7.1.3.",{"author":69},[71,55,83],"nuxt","2026-10-09T07:14:08.209884+00:00",{"id":86,"slug":87,"title":88,"excerpt":89,"meta_title":90,"meta_description":91,"featured_image":51,"fields":92,"tags":93,"published":47,"published_at":95,"created_at":95,"updated_at":95},"4b57ca81-a3e2-4785-a023-dcbdf8c077d5","notes/weekly-roundup-2026-10-02","Weekly round-up: Postgres security release, OrioleDB beta, and Supabase Middleware 1.0","Supabase's Postgres security release with four breaking changes, OrioleDB in public beta, Supabase Middleware 1.0, and a note on WordPress 7.1.2.","Weekly Round-Up: Postgres Release, OrioleDB Beta","This week: Supabase's Postgres 17.11 security release and its four breaking changes, OrioleDB public beta, and Supabase Middleware 1.0.",{"author":69},[71,55,94],"wordpress","2026-10-02T07:13:16.097003+00:00",{"id":4,"slug":5,"title":6,"excerpt":7,"meta_title":8,"meta_description":9,"featured_image":51,"fields":97,"tags":98,"published":47,"published_at":57,"created_at":58,"updated_at":59},{"author":53},[55,56],{"id":100,"slug":101,"title":102,"excerpt":103,"meta_title":104,"meta_description":105,"featured_image":51,"fields":106,"tags":107,"published":47,"published_at":108,"created_at":108,"updated_at":109},"d75fb417-2460-4469-b103-4e062f46d229","notes/weekly-roundup-2026-09-25","Weekly round-up: a critical WordPress RCE, Nuxt's build layer swap, and Claude gets serious about small business","A critical WordPress RCE worth patching today, Nuxt 4.5's build layer swap, Claude for Small Business grows up, and a quick look at this month's Supabase changelog.","Weekly Round-Up: WordPress RCE, Nuxt 4.5, Claude for SMBs","This week: a critical WordPress RCE worth patching today, Nuxt 4.5's new build layer, Claude for Small Business grows up, and a Supabase changelog look.",{"author":53},[71,94,83,56,55],"2026-09-25T07:19:43.316037+00:00","2026-10-01T19:41:42.773395+00:00",{"id":111,"slug":112,"title":113,"excerpt":114,"meta_title":115,"meta_description":116,"featured_image":51,"fields":117,"tags":118,"published":47,"published_at":119,"created_at":120,"updated_at":109},"37675193-0337-4634-bafa-c503df69b0c6","notes/weekly-roundup-2026-09-18","Weekly round-up: StyleSmuggler clean-up, a Supabase deadline, and the Claude Code limits shuffle","A week on from the Magento zero day, the mopping-up is where the real work is. Plus a Supabase logs endpoint being removed on 23 September, and the Claude Code limits change that is both a rise and a cut.","Round-up: StyleSmuggler clean-up and a Supabase deadline","The week after the Magento zero day: patching is the easy part, Supabase removes logs.all on 23 September, and Claude Code's limits moved.",{"author":53},[71,72,55,56],"2026-09-19T06:13:53.415+00:00","2026-09-18T06:10:00+00:00",1792137657220]