[{"data":1,"prerenderedAt":663},["ShallowReactive",2],{"blog-en-rotate-supabase-service-role-key":3,"blog-index-en":422},{"id":4,"title":5,"body":6,"category":379,"cover":380,"coverAlt":381,"description":382,"draft":383,"extension":384,"faq":385,"image":400,"keywords":401,"meta":410,"navigation":411,"ogTitle":412,"path":413,"published":414,"seo":415,"stem":416,"tldr":417,"updated":414,"__hash__":421},"blog_en\u002Fblog\u002Frotate-supabase-service-role-key.md","How to rotate a leaked Supabase service_role key",{"type":7,"value":8,"toc":364},"minimark",[9,24,27,30,33,41,52,55,70,81,85,88,95,101,104,110,114,120,123,148,151,154,161,170,176,206,217,222,230,240,244,247,265,275,281,285,288,291,294,303,307,310,313,319,323,354],[10,11,12,13,17,18,23],"p",{},"Somebody has told you that your Supabase ",[14,15,16],"code",{},"service_role"," key is sitting in your\napp where anyone can read it. Before you change anything, be certain that is the\nkey they found: ",[19,20,22],"a",{"href":21},"\u002F#scan","our free scan"," reads your live site the way a stranger\nwould and tells you which Supabase key it can actually see there, with no\naccount and nothing to install.",[10,25,26],{},"The advice that follows a finding like that is almost always one word: rotate.\nThen you go looking for how, and the sources disagree. Supabase's own\ndocumentation opens its rotation guide by telling you to fix the root cause of\nthe leak before you begin. Half a dozen third-party guides tell you to rotate\nimmediately and ask questions afterwards.",[10,28,29],{},"Here is the part neither of them writes down: both are correct about different\nsituations, and the question that separates them is where the key leaked to.",[10,31,32],{},"One thing to have straight before any of it. Deleting the key from your code\ntakes your own copy off the ring. Rotating is changing the lock. Only the second\none reaches the copies other people already have.",[34,35,37,38,40],"h2",{"id":36},"is-it-really-the-service_role-key","Is it really the ",[14,39,16],{}," key?",[10,42,43,44,47,48,51],{},"In a newer project the first few characters answer it. ",[14,45,46],{},"sb_secret_"," at the start\nis the secret one. ",[14,49,50],{},"sb_publishable_"," is the key that is supposed to be in your\napp, and finding it there is not a finding at all.",[10,53,54],{},"Be sure before you do anything disruptive, because the key found in a\nvibe-coded app is usually the one that belongs there.",[10,56,57,58,61,62,64,65,69],{},"Older projects issue a different pair, ",[14,59,60],{},"anon"," and ",[14,63,16],{},", and those two\nlook almost identical: same format, same length, no prefix to read. The middle\nsection of one of those keys is not encrypted at all. It decodes to a few lines\nof plain text, and one of them states the role.\n",[19,66,68],{"href":67},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Which API keys are safe in your frontend","\nwalks through both checks.",[10,71,72,73,75,76,80],{},"The reason to be sure is that this is rarer than the warnings suggest. We\nscanned 30,998 live vibe-coded apps in August 2026 and found a ",[14,74,16],{},"\nkey shipped in 3 of them. A Google API key, which is usually harmless and often\nlocked to one domain, turned up in 1,142.\n",[19,77,79],{"href":78},"\u002Fresearch\u002Fvibe-coded-app-security-2026","The full count is here",".",[34,82,84],{"id":83},"rotate-first-or-fix-the-leak-first","Rotate first, or fix the leak first?",[10,86,87],{},"It depends on whether the key is already public, and the line between the two\ncases is clean.",[10,89,90,94],{},[91,92,93],"strong",{},"If the key is in the JavaScript your visitors download, it is public now.","\nAnybody who loaded your site while it was live has a copy, and so does every\nautomated crawler that went looking for exactly that string. Nothing you change\nin your code reaches those copies. Rotate first, then fix the source.",[10,96,97,100],{},[91,98,99],{},"If it only reached a private repository, a log file, a CI variable or a chat\nmessage, the exposure is bounded."," Rotate first here and you will be doing it\ntwice, because the next deploy pushes the old value back out of whatever\nproduced it and your new key follows the old one out. Fix the source, then\nrotate.",[10,102,103],{},"Supabase's guide is written for the second case. The urgent guides are written\nfor the first. If you are reading this because a scanner found the key on your\nlive URL, you are in the first case.",[105,106],"diagram",{"alt":107,"caption":108,"src":109},"Two lanes. The top lane starts at a browser window and runs through step one, a key with a rotation arrow, then step two, a pair of angle brackets. The bottom lane starts at a file and runs through the same two steps in the opposite order, brackets first and key second.","Same two jobs, opposite order. What decides it is whether the leaked copy is already out in the world.","\u002Fblog\u002Frotate-supabase-service-role-key\u002Ftwo-orders-1600x640.png",[34,111,113],{"id":112},"how-to-rotate-a-supabase-secret-key","How to rotate a Supabase secret key",[10,115,116,117,119],{},"If your project has ",[14,118,46],{}," keys, this is a dashboard job with no downtime.",[10,121,122],{},"A project can hold more than one secret key at a time, each with its own name,\nand that is what makes it safe: you add the new one before you take the old one\naway, so nothing is broken in between.",[124,125,126,134,142,145],"ol",{},[127,128,129,130,133],"li",{},"Open your project, go to ",[91,131,132],{},"Settings → API Keys"," and create a new secret key.",[127,135,136,137,141],{},"Put it everywhere the old one was used, all of which should be on a server:\nedge functions, webhooks, scheduled jobs, a backend of your own.\n",[19,138,140],{"href":139},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Where those values live"," if you have\nnot opened that page before.",[127,143,144],{},"Deploy, then click through the parts of your app that read and write data. A\nwrong secret key fails loudly and immediately, which is the good case.",[127,146,147],{},"Only then delete the compromised key.",[10,149,150],{},"Step 4 is permanent. Supabase deletes a secret key outright: no undo, no\nre-enable, no parked copy you can bring back. That is why it goes last.",[10,152,153],{},"Deleting a secret key does not sign your users out. An API key says which\napplication is calling your database, and a visitor's session token says which\nuser they are. The second is checked against your project's signing key, and\nthat is a separate value you have not touched.",[34,155,157,158,160],{"id":156},"why-a-legacy-supabase-service_role-key-cannot-be-rotated","Why a legacy Supabase ",[14,159,16],{}," key cannot be rotated",[10,162,163,164,166,167,169],{},"Because there is no button for it. Supabase's troubleshooting note says direct\nrotation of the legacy ",[14,165,60],{},", ",[14,168,16],{}," and JWT secrets is no longer\nsupported, and points you at the new keys instead.",[10,171,172,173,175],{},"So invalidating a leaked legacy ",[14,174,16],{}," key is a migration rather than a\nrotation:",[124,177,178,189,195,200],{},[127,179,180,183,184,61,186,188],{},[91,181,182],{},"Create the new keys."," This adds ",[14,185,50],{},[14,187,46],{},"\nalongside the old pair. Both systems work at once and nothing breaks.",[127,190,191,194],{},[91,192,193],{},"Move your frontend onto the publishable key."," In Lovable or Bolt this is\nusually one value in your project settings rather than a line of code.",[127,196,197],{},[91,198,199],{},"Move every server-side use onto the secret key.",[127,201,202,205],{},[91,203,204],{},"Disable the legacy keys"," in your project settings.",[10,207,208,209,61,211,213,214,216],{},"Step 4 is one switch and it covers both old keys. ",[14,210,60],{},[14,212,16],{}," are\nJWTs signed by the same secret, so the switch that revokes one revokes the\nother, and a frontend still carrying the old ",[14,215,60],{}," key stops working the moment\nyou flip it. That is why step 2 comes before it.",[105,218],{"alt":219,"caption":220,"src":221},"A settings panel with four rows. The top two, sb_publishable_ and sb_secret_, each carry a filled dot and a value you can read. Below a divider, anon and service_role are drawn faded with their values masked as dots, and a bracket joins both of those rows to one toggle switch in the off position.","Disabling the legacy keys is one control for both of them. The anon key your app is using goes out with the service_role key you are trying to invalidate.","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fone-switch-two-keys-1600x720.png",[10,223,224,225,229],{},"Deactivation is reversible, which is the one piece of good news here: if\nsomething you forgot turns out to still be using a legacy key, you can switch\nthem back on while you fix it.\n",[19,226,228],{"href":227},"\u002Fblog\u002Fsupabase-new-api-keys","What the migration involves"," has the longer\nversion.",[231,232,234],"callout",{"type":233},"warn",[10,235,236,239],{},[91,237,238],{},"Until step 4, the leaked key still works."," Steps 1 to 3 add a second way in;\nthey take nothing away. On a project where the key is already public, that is\nwhat makes this order uncomfortable, and it is the reason to do the four steps\nback to back. A half-finished migration leaves the old key live and your app\nrunning on two key systems at once.",[34,241,243],{"id":242},"where-the-key-leaked-from-and-how-to-close-it","Where the key leaked from, and how to close it",[10,245,246],{},"Three causes account for nearly all of it, and all three are inside your own\nproject.",[10,248,249,260,261,264],{},[91,250,251,252,255,256,259],{},"A ",[14,253,254],{},"VITE_"," or ",[14,257,258],{},"NEXT_PUBLIC_"," prefix."," These are not a security setting\nsomebody forgot to switch on. They are an instruction to the build: put this\nvalue in the bundle. A variable named ",[14,262,263],{},"VITE_SUPABASE_SERVICE_ROLE_KEY"," was\ncompiled into your JavaScript on purpose, by a tool doing exactly what it was\ntold to do.",[10,266,267,270,271,274],{},[91,268,269],{},"A value pasted straight into a component."," No prefix involved and no ",[14,272,273],{},".env","\nfile, just the key sitting in a line of code because that was the quickest way\nto make a query return something.",[10,276,277,280],{},[91,278,279],{},"Work that belongs on a server."," Deleting an account, writing to a table your\nusers are not allowed to write to, reading rows across everybody. The key got\nreached for because the browser could not do the job, and the fix is to move the\njob: an edge function, a serverless route, anything your visitors do not\ndownload.",[34,282,284],{"id":283},"how-do-i-know-if-someone-used-it","How do I know if someone used it?",[10,286,287],{},"Usually you cannot be certain. What you can do is narrow the window and look\ninside it.",[10,289,290],{},"The window opens with the deploy that first shipped the key and closes when you\ndisabled it. Your Supabase project keeps logs for both the API and the database,\nand that date range is what to filter them to. What you are looking for is reads\nand writes you cannot account for: requests to tables your app never touches,\ntraffic at hours nobody was using it, deletes nobody made.",[10,292,293],{},"Then check the data itself. Row counts against what you expect, your own account\nrecords, anything with a timestamp that moved while nobody was working. A\nsupport message about data that changed on its own is how most of these are\nactually discovered, and it arrives weeks later.",[10,295,251,296,298,299,80],{},[14,297,16],{}," key does not reach your payment provider or your mail sender.\nIt is still worth knowing whether it was the only key in your bundle, because\nthe ones that spend money leak the same way:\n",[19,300,302],{"href":301},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","what 30,998 apps were shipping",[34,304,306],{"id":305},"check-your-live-app-before-you-call-it-done","Check your live app before you call it done",[10,308,309],{},"Load your site in a private window, open the JavaScript your browser downloaded,\nand search it for the old value. Then search for the new one, which should not\nbe there either.",[10,311,312],{},"Two things make this worth checking by hand. A build can serve a cached bundle\nfor a while after you deploy, so the file a visitor gets is not always the file\nyou just built. And a key can be in more than one place: a second entry point, a\nservice worker, an old build still being served from a path nobody links to.",[10,314,315,316,80],{},"Our free scan does this part from outside, on the URL your visitors actually\nuse, and it decodes a Supabase key far enough to read the role, so a publishable\nkey comes back as a tick. It takes about twenty seconds and needs no account:\n",[19,317,318],{"href":21},"scan your app",[34,320,322],{"id":321},"what-to-do-now","What to do now",[324,325,326],"key-takeaways",{},[327,328,329,339,342,345,348,351],"ul",{},[127,330,331,332,334,335,338],{},"Confirm the key first. ",[14,333,46],{}," at the front, or ",[14,336,337],{},"\"role\": \"service_role\""," inside an older one. A publishable key in your frontend is not a finding.",[127,340,341],{},"If it is in the bundle your visitors download, rotate before you change any code. Editing your app does not reach the copies already out there.",[127,343,344],{},"If it only leaked to a repo, a log or a chat, fix the source first, so your next deploy does not push the new key straight back out.",[127,346,347],{},"On a newer project: create a second secret key, move your server code onto it, deploy, then delete the old one. Deleting is permanent.",[127,349,350],{},"On a legacy project there is no rotate button. Create the new keys, move your frontend and your server onto them, then disable the old pair with the one switch that covers both.",[127,352,353],{},"Search your live bundle afterwards. A cached build can serve the old value for a while after you deploy.",[10,355,251,356,358,359,363],{},[14,357,16],{}," key reads and writes every row in your database. The worst\nversion of this story ends with an empty table, and whether those rows come back\ndepends on\n",[19,360,362],{"href":361},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","what you were backing up","\nbefore any of it happened.",{"title":365,"searchDepth":366,"depth":366,"links":367},"",3,[368,371,372,373,375,376,377,378],{"id":36,"depth":369,"text":370},2,"Is it really the service_role key?",{"id":83,"depth":369,"text":84},{"id":112,"depth":369,"text":113},{"id":156,"depth":369,"text":374},"Why a legacy Supabase service_role key cannot be rotated",{"id":242,"depth":369,"text":243},{"id":283,"depth":369,"text":284},{"id":305,"depth":369,"text":306},{"id":321,"depth":369,"text":322},"Security basics","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcover-1200x630.png","A padlock with two identical keys beside it, drawn at the same size, one bright and one faded.","Supabase says fix the leak first. Other guides say rotate now. Which is right depends on where your service_role key leaked.",false,"md",[386,389,392,395,397],{"q":387,"a":388},"Does rotating the key break my live app?","Not if you do it in order. On a project with the newer keys you add a second secret key, move your server code onto it, deploy, and only then delete the old one, so there is never a moment with no working key. On a legacy project the risk is a different one: disabling the old pair also disables the anon key your frontend uses, so your app breaks unless it is already on the publishable key when you flip that switch.",{"q":390,"a":391},"Can I rotate the legacy anon and service_role keys?","No. Supabase's troubleshooting documentation says direct rotation of the legacy anon, service_role and JWT secrets is no longer supported. Invalidating a leaked legacy key means creating the new sb_publishable_ and sb_secret_ keys, moving your app and your server code onto them, and then disabling the old pair in your project settings.",{"q":393,"a":394},"Should I delete the old key or deactivate it?","You do not get to choose, because the two key systems behave differently. A newer sb_secret_ key is deleted, permanently, with no way to bring it back. The legacy pair is deactivated instead, and deactivation is reversible: if something you forgot turns out to still be using an old key, you can switch them back on while you fix it.",{"q":284,"a":396},"Usually you cannot be certain. Narrow it to a window instead: the key was usable from the deploy that first shipped it until the moment you disabled it. Filter your Supabase API and database logs to that range and look for reads and writes you cannot account for, then check your data for row counts and timestamps that do not match anything you did.",{"q":398,"a":399},"Do I need to rotate my anon key too?","On a legacy project you do not get a choice: disabling the old pair takes both keys at once, so your frontend needs the new publishable key before you flip the switch. On a newer project the publishable key is meant to be public and there is no reason to touch it. What is worth checking either way is Row Level Security, because that is the only thing standing between a publishable key and your whole database.","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",[402,403,404,405,406,407,408,409],"rotate supabase service role key","how to rotate service role key in supabase","supabase service role key leaked","supabase service role key exposed","supabase key rotation","revoke supabase api key","supabase legacy api keys deactivate","service role key in frontend",{},true,"Rotate a leaked Supabase service_role key, in the right order","\u002Fblog\u002Frotate-supabase-service-role-key","2026-09-08",{"title":5,"description":382},"blog\u002Frotate-supabase-service-role-key",[418,419,420],"If your Supabase service_role key is in the JavaScript a browser downloads, rotate it before you fix anything. The copy already out there does not expire.","If it only reached a private repo or a log, fix the source first, or your new key follows the old one out on the next deploy.","A legacy service_role key cannot be rotated at all. Invalidating one means creating the new sb_secret_ keys, moving your app onto them, and disabling the old pair with a switch that covers both.","tBQe2ywJbNRQUJosmS5i4wphNWbdSxUAnELrMflF_y0",[423,430,436,442,448,454,460,466,472,478,484,490,496,502,508,514,515,521,527,533,539,545,550,556,562,568,574,579,585,591,597,603,609,615,621,627,632,637,643,649,654,659],{"path":424,"title":425,"description":426,"published":427,"category":428,"image":429,"draft":383},"\u002Fblog\u002Fsupabase-backup-auth-users","Why your Supabase dump has no users in it","Run supabase db dump on its own and you get the shape of your database and none of its rows, with the auth schema your users live in left out entirely.","2026-09-23","Backups","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":431,"title":432,"description":433,"published":434,"category":379,"image":435,"draft":383},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domain expired, website down: what actually happens next","Your domain expired and your website is down. Here is the clock you are on, why a lapsed certificate is the easier of the two, and how to check both.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":437,"title":438,"description":439,"published":440,"category":379,"image":441,"draft":383},"\u002Fblog\u002Fis-lovable-safe","Is Lovable safe? What 18,554 live Lovable apps showed","Is Lovable safe? We ran nine checks on 18,554 live Lovable apps. The platform was the cleanest of five builders. Every finding was inside the app itself.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":443,"title":444,"description":445,"published":446,"category":379,"image":447,"draft":383},"\u002Fblog\u002Fvibe-coded-app-security-checklist","The vibe coding security checklist, in nine checks","A vibe coding security checklist with nine items, each one something anyone can verify about your live app from outside, and each with a one-line test.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":449,"title":450,"description":451,"published":452,"category":379,"image":453,"draft":383},"\u002Fblog\u002Fstripe-secret-key-in-frontend","A Stripe secret key exposed in your frontend can move money","A Stripe secret key exposed in your frontend can refund, charge and read every customer record you hold. Your pk_live_ key is meant to be there.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":455,"title":456,"description":457,"published":458,"category":379,"image":459,"draft":383},"\u002Fblog\u002Fvite-and-next-public-env-vars","Vite env variables exposed: VITE_ and NEXT_PUBLIC_ mean publish this","Vite env variables exposed in your app did what the prefix asked. VITE_ and NEXT_PUBLIC_ mean publish this, and the AI that added one never knew the cost.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":461,"title":462,"description":463,"published":464,"category":379,"image":465,"draft":383},"\u002Fblog\u002Fbase44-source-maps","Base44 security: what a scan flags, and what is yours to fix","Base44 security on 5,438 scanned apps: three findings on nearly every one are the platform's, the source map is Base44's badge, and what is yours is short.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":467,"title":468,"description":469,"published":470,"category":379,"image":471,"draft":383},"\u002Fblog\u002Fis-cursor-ai-safe","Is Cursor AI safe? The editor, the code, and the app you shipped","Is Cursor AI safe? Three questions in one search: what Cursor keeps, what the code it writes gets wrong, and whether the app you shipped is open.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":473,"title":474,"description":475,"published":476,"category":379,"image":477,"draft":383},"\u002Fblog\u002Fis-replit-safe","Is Replit safe? What we found in 3,042 live Replit apps","Is Replit safe? We ran nine external checks on 3,042 live Replit apps. The host was not where the findings were. The app each owner published was.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":479,"title":480,"description":481,"published":482,"category":428,"image":483,"draft":383},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: why your database copy has no files","A Supabase storage backup is a separate job. Database backups keep the list of your files and none of the files, so a restore leaves every upload broken.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":485,"title":486,"description":487,"published":488,"category":428,"image":489,"draft":383},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Supabase point-in-time recovery: what it costs, what it misses","Supabase point-in-time recovery rewinds your database to any second in the last week. It costs $100 a month on top of Pro, and it covers your database only.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":491,"title":492,"description":493,"published":494,"category":428,"image":495,"draft":383},"\u002Fblog\u002Fsupabase-project-paused-recover","Supabase project paused? Your data is still there","Supabase paused your project after a week of inactivity. Nothing is deleted, Restore sits beside the project name, and you have a year before that changes.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":497,"title":498,"description":499,"published":500,"category":379,"image":501,"draft":383},"\u002Fblog\u002Fsafest-ai-app-builder","Which AI app builder is safest? We scanned 30,998 apps","Which AI app builder is safest? We scanned 30,998 live apps from Lovable, Base44, Replit, v0 and Bolt. The builder is not what decides your grade.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":503,"title":504,"description":505,"published":506,"category":379,"image":507,"draft":383},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Enable Row Level Security on every Supabase table, then prove it","Enabling Row Level Security in Supabase with no policy locks a table completely. A policy without the setting does nothing. Here is the SQL, and the test.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":509,"title":510,"description":511,"published":512,"category":379,"image":513,"draft":383},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": what the warning misses","Supabase reports \"RLS disabled in public\" as an error. It says nothing about the read policy that leaves your table just as open to strangers.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":413,"title":5,"description":382,"published":414,"category":379,"image":400,"draft":383},{"path":516,"title":517,"description":518,"published":519,"category":379,"image":520,"draft":383},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Vibe coding security scanners compared, including ours","The best vibe coding security scanner comes down to three questions no feature list answers. Ten tools compared, with prices, and the jobs Reeve does not do.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":522,"title":523,"description":524,"published":525,"category":379,"image":526,"draft":383},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: run the five checks yourself","A Supabase security checker reads your published app instead of your project settings. Here are the five checks it runs, and how to run each one yourself.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":528,"title":529,"description":530,"published":531,"category":379,"image":532,"draft":383},"\u002Fblog\u002Fvibe-coding-security-scanner","Vibe coding security scanner: what a URL scan misses","A vibe coding security scanner reads your live app from outside. Here is what that covers, the four things it cannot see, and how to read the result.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":534,"title":535,"description":536,"published":537,"category":379,"image":538,"draft":383},"\u002Fblog\u002Fmissing-security-headers","Missing security headers: when it actually matters","Missing security headers is the finding our scanner prints most. Here is what it protects against, and when it is the least urgent line on your report.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":540,"title":541,"description":542,"published":543,"category":379,"image":544,"draft":383},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Your OpenAI API key is exposed in your frontend. Rotate it.","An OpenAI API key exposed in your frontend cannot be locked to a domain. Rotate it today, move the call behind your own endpoint, and cap the spend.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":301,"title":546,"description":547,"published":548,"category":379,"image":549,"draft":383},"An API key exposed in your frontend: what 30,998 apps shipped","An API key exposed in your frontend is usually a Google Maps key. We scanned 30,998 live vibe-coded apps and counted which secrets actually leak.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":551,"title":552,"description":553,"published":554,"category":428,"image":555,"draft":383},"\u002Fblog\u002Fsupabase-backup-tools-compared","Supabase backup tools compared, including ours","Four kinds of Supabase backup tool, what each one actually copies, and the case where a free GitHub Action beats paying anyone, us included.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":557,"title":558,"description":559,"published":560,"category":379,"image":561,"draft":383},"\u002Fblog\u002Freplit-secrets-explained","How to use secrets in Replit, and what still gets published","How to use secrets in Replit: add one, read it back, and fix the two reasons it comes back undefined. Plus the keys the Secrets tool cannot keep private.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":563,"title":564,"description":565,"published":566,"category":428,"image":567,"draft":383},"\u002Fblog\u002Fback-up-supabase-free-tier","Supabase free tier backups: how to make one without a terminal","There are no Supabase free tier backups, so the copy has to come from you. How to make one from the dashboard, and what CSV leaves out.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":569,"title":570,"description":571,"published":572,"category":379,"image":573,"draft":383},"\u002Fblog\u002Fis-supabase-secure","Is Supabase secure? Yes. Your project is a separate question","Is Supabase secure? The platform is audited, encrypted and pen-tested. Their own compliance documents say where that stops and your settings begin.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":139,"title":575,"description":576,"published":577,"category":379,"image":578,"draft":383},"Where to find your Supabase API keys: anon, service_role and the URL","Your Supabase project URL, anon key and service_role key are on one dashboard page. Here is where that page is, and which of the four belongs in your app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":580,"title":581,"description":582,"published":583,"category":379,"image":584,"draft":383},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy in Supabase. Now what?","\"New row violates row-level security policy\" means Supabase refused a write. The fix that clears it in ten seconds also reopens the table to everyone.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":586,"title":587,"description":588,"published":589,"category":379,"image":590,"draft":383},"\u002Fblog\u002Fcors-wildcard-security-risk","Is a CORS wildcard a security risk? Usually not.","Is a CORS wildcard a security risk? Usually it is your builder default, and it gives away nothing your server was not already handing to anyone who asked.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":592,"title":593,"description":594,"published":595,"category":428,"image":596,"draft":383},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Supabase branching is not a backup. It only goes forwards.","Supabase branching is not a backup: a branch starts with none of your data, and merging only moves schema. What it is for, and what to use instead.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":598,"title":599,"description":600,"published":601,"category":428,"image":602,"draft":383},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","How to restore a Supabase backup, and what breaks after","How to restore a Supabase backup from the dashboard or from a dump file, what the restore replaces, and why your app can still be broken when it finishes.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":604,"title":605,"description":606,"published":607,"category":379,"image":608,"draft":383},"\u002Fblog\u002Fsupabase-storage-bucket-public","Your Supabase storage bucket is public. Is that a problem?","A public Supabase storage bucket means anyone with a file URL can open it. It does not mean anyone can list what is in there. Two different settings.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":610,"title":611,"description":612,"published":613,"category":379,"image":614,"draft":383},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Is a Google API key exposed in your frontend a problem?","A Google API key exposed in your frontend is the key our scanner finds most often, and usually it is fine. One free setting decides which it is.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":616,"title":617,"description":618,"published":619,"category":428,"image":620,"draft":383},"\u002Fblog\u002Fai-agent-deleted-my-database","An AI agent deleted my Supabase data. What can I recover?","An AI agent deleted your database data. What you can recover was decided before it ran, and the next few minutes decide how much of it survives.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":622,"title":623,"description":624,"published":625,"category":379,"image":626,"draft":383},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Can anyone read your Supabase database? We checked 3,680 apps","Can anyone read your Supabase database without logging in? We scanned 30,998 live apps built with AI builders and measured how often the answer is yes.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":628,"title":629,"description":630,"published":625,"category":379,"image":631,"draft":383},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps exposed: your app is publishing its original code","An exposed source map lets anyone read your app's original code, comments included. The 30-second check, and what actually matters if yours are public.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":227,"title":633,"description":634,"published":635,"category":379,"image":636,"draft":383},"Supabase's new API keys: which one is safe in your app?","Supabase replaced anon and service_role with publishable and secret keys. Which one belongs in your app, and which never does?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":638,"title":639,"description":640,"published":641,"category":428,"image":642,"draft":383},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Does Supabase back up my database? It depends on your plan.","Does Supabase back up your database? Daily on paid plans, and not at all on the free one. How to check which you have, and what that copy cannot survive.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":644,"title":645,"description":646,"published":647,"category":379,"image":648,"draft":383},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security is on. Your table is still public.","Turning on Supabase Row Level Security does not protect a table. Your policies do, and the policy that fixed your broken app may let everyone in.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":650,"title":651,"description":652,"published":647,"category":428,"image":653,"draft":383},"\u002Fblog\u002Fversion-history-is-not-a-backup","Version history is not a backup. It cannot undo a deleted table.","Lovable and Bolt keep version history for your code. Your database is a separate service, so rolling back to this morning does not bring your data back.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":361,"title":655,"description":656,"published":657,"category":428,"image":658,"draft":383},"Three ways to back up a Supabase database, and what each misses","The dashboard, pg_dump, and a managed service. What each one actually saves, what it quietly leaves out, and which one survives losing the account.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":67,"title":660,"description":661,"published":657,"category":379,"image":662,"draft":383},"Which API keys are safe in your frontend, and which aren't","Your Supabase anon key is supposed to be public. Your service_role key is not, and it ignores every rule you set. Here is how to tell them apart.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1790150951364]