[{"data":1,"prerenderedAt":870},["ShallowReactive",2],{"blog-en-vibe-coded-app-security-checklist":3,"blog-index-en":636},{"id":4,"title":5,"body":6,"category":588,"cover":589,"coverAlt":590,"description":591,"draft":592,"extension":593,"faq":594,"image":613,"keywords":614,"meta":624,"navigation":625,"ogTitle":626,"path":627,"published":628,"seo":629,"stem":630,"tldr":631,"updated":628,"__hash__":635},"blog_en\u002Fblog\u002Fvibe-coded-app-security-checklist.md","The vibe coding security checklist, in nine checks",{"type":7,"value":8,"toc":565},"minimark",[9,13,21,24,27,32,35,41,185,194,198,201,209,214,226,242,260,264,272,275,288,292,301,312,320,324,327,335,343,347,350,353,357,360,363,371,375,378,381,389,393,396,399,407,411,414,417,421,424,427,432,436,439,442,450,466,469,473,476,479,485,489,492,495,505,512,516,552],[10,11,12],"p",{},"You are about to send your app's address to somebody, and a small voice says\nyou should check it first. So you search for a vibe coding security checklist\nand find one with twenty-five items on it, written by a person who assumes you\nalready know what a Content Security Policy is.",[10,14,15,16,20],{},"Here is the part that list after list gets wrong: ",[17,18,19],"strong",{},"most of what is on them\ncannot be checked."," \"Use strong passwords\" is advice. \"Clean up dead code\" is\nhousekeeping. \"Follow the principle of least privilege\" is a sentence. None of\nthem has a test, so none of them can be finished, and a list you cannot finish\nis a worry with numbers on it.",[10,22,23],{},"This one has nine items. Nine is how many things about a live app anybody can\nverify from outside it, without your password, your repository or your Supabase\naccount. Each one has a test you can run yourself and each test comes back yes\nor no.",[10,25,26],{},"Think of it as the walk a pilot does around an aircraft before a flight. It is\nshort, everything on it is visible from the tarmac, and it replaces nothing in\nthe maintenance log. The last section of this post is about the log.",[28,29,31],"h2",{"id":30},"what-should-be-on-a-vibe-coding-security-checklist","What should be on a vibe coding security checklist?",[10,33,34],{},"Nine questions, and they are the nine a stranger could ask about your app this\nafternoon whether you checked or not.",[36,37],"diagram",{"alt":38,"caption":39,"src":40},"The Reeve mark above a row of nine outlined icons: a key, a database cylinder, a document, a padlock, a lidded box, a pair of code brackets, a globe, a certificate rosette, and a calendar.","The nine, in the order the sections below work through them. Every one is read from outside, which is what makes each of them testable.","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fnine-checks-1600x420.png",[42,43,44,60],"table",{},[45,46,47],"thead",{},[48,49,50,54,57],"tr",{},[51,52,53],"th",{},"The check",[51,55,56],{},"The test you can run yourself",[51,58,59],{},"What it means if it comes back wrong",[61,62,63,89,100,119,130,141,152,163,174],"tbody",{},[48,64,65,69,86],{},[66,67,68],"td",{},"Secret keys in your code",[66,70,71,72,76,77,76,80,76,83],{},"Search the project for ",[73,74,75],"code",{},"sk_",", ",[73,78,79],{},"sb_secret_",[73,81,82],{},"service_role",[73,84,85],{},"AKIA",[66,87,88],{},"Whoever finds it can spend your money or read every row",[48,90,91,94,97],{},[66,92,93],{},"Database rules",[66,95,96],{},"Supabase, then the Security Advisor",[66,98,99],{},"Anyone holding your public key can read those rows",[48,101,102,105,116],{},[66,103,104],{},"Private files",[66,106,107,108,111,112,115],{},"Open ",[73,109,110],{},"\u002F.env"," and ",[73,113,114],{},"\u002F.git\u002Fconfig"," in a private window",[66,117,118],{},"Every key you thought was on the server is downloadable",[48,120,121,124,127],{},[66,122,123],{},"Storage buckets",[66,125,126],{},"Supabase, then Storage, then the Public column and the policies",[66,128,129],{},"A stranger gets the list of what your users uploaded",[48,131,132,135,138],{},[66,133,134],{},"Browser safety headers",[66,136,137],{},"A scan; there is no address-bar version of this one",[66,139,140],{},"Your visitors are easier to attack through your page",[48,142,143,146,149],{},[66,144,145],{},"Published source maps",[66,147,148],{},"Browser developer tools, Sources, look for your own filenames",[66,150,151],{},"Your original code is readable, comments and all",[48,153,154,157,160],{},[66,155,156],{},"Your own API addresses",[66,158,159],{},"Open one in a private window where you are not signed in",[66,161,162],{},"Whatever it hands back is public",[48,164,165,168,171],{},[66,166,167],{},"Certificate expiry",[66,169,170],{},"Click the padlock, open the certificate, read \"Valid until\"",[66,172,173],{},"Visitors meet a full-page browser warning instead of a page",[48,175,176,179,182],{},[66,177,178],{},"Domain renewal",[66,180,181],{},"Your registrar's expiry date, and whether auto-renew is on",[66,183,184],{},"The app disappears and the name goes on sale",[10,186,187,188,193],{},"Our own ",[189,190,192],"a",{"href":191},"\u002Fsecurity-scanner","free security scanner"," runs all nine on any live URL\nin about 20 seconds with no account, which is the fastest way to do the first\npass. It reads, it never signs in, and it never writes anything. Every item\nbelow is still something you can check by hand, and the tests are written out so\nyou can hold a line of our report against your own dashboard.",[28,195,197],{"id":196},"the-four-to-run-before-you-share-the-url","The four to run before you share the URL",[10,199,200],{},"Secret keys, database rules, private files and storage buckets. These four are\nwhere the thing exposed is your data or your money, and all four are yours to\nfix rather than your hosting platform's.",[10,202,203,204,208],{},"Three of them are the only checks in the whole set that can report a critical\nfinding, and the fourth is the one where what is exposed is what your users\nuploaded. Between 12 and 14 August 2026 we ran all nine checks over\n",[189,205,207],{"href":206},"\u002Fresearch\u002Fvibe-coded-app-security-2026","30,998 live vibe-coded apps",", and the\nfigures in each section below come from that run.",[210,211,213],"h3",{"id":212},"_1-is-a-secret-key-in-the-code-your-app-ships","1. Is a secret key in the code your app ships?",[10,215,216,217,76,219,76,221,111,223,225],{},"Search your whole project for ",[73,218,75],{},[73,220,79],{},[73,222,82],{},[73,224,85],{},". A\nmatch inside anything the browser downloads is the finding.",[10,227,228,229,232,233,236,237,241],{},"Everything your app needs to run in a browser arrives in that browser, so a key\nsitting in it arrives too. Some keys belong there: a Supabase ",[73,230,231],{},"anon"," or\n",[73,234,235],{},"sb_publishable_"," key is an address rather than a permission, and finding one is\ncorrect.\n",[189,238,240],{"href":239},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Which keys are safe in a frontend and which are not","\nis the whole of that distinction.",[10,243,244,245,247,248,250,251,254,255,259],{},"A secret key is the other kind. A Supabase ",[73,246,79],{}," or ",[73,249,82],{}," key\nignores every table rule you have ever written. A Stripe ",[73,252,253],{},"sk_live_"," key moves\nmoney. We found a key of that class on 52 apps out of 30,998, which is rare and\nis the worst thing on this list when it happens. If yours is one of them,\n",[189,256,258],{"href":257},"\u002Fblog\u002Frotate-supabase-service-role-key","rotate before you do anything else",":\ndeleting the key from your code leaves the old value working.",[210,261,263],{"id":262},"_2-can-a-stranger-read-your-database","2. Can a stranger read your database?",[10,265,266,267,271],{},"In Supabase, open the Security Advisor. Every entry saying a table is public but\nrow level security has not been enabled is a table answering anyone who asks,\nand ",[189,268,270],{"href":269},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","that exact warning"," has an article of\nits own.",[10,273,274],{},"Row Level Security is the rule that decides, row by row, who may see what.\nWithout it, the publishable key sitting in your app is enough to read the table,\nand that key is in every visitor's browser by design.",[10,276,277,278,282,283,287],{},"This is the commonest serious finding in the whole set: 2,096 of the 3,680 apps\nwhose Supabase project answered us, or 57%, had at least one table handing rows\nto a request with nobody signed in.\n",[189,279,281],{"href":280},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Turning it on for every table"," is the\nfix. The advisor reads your settings rather than your database's answers, so\nfinish by checking from outside: a table can have the setting on and a policy\nthat ",[189,284,286],{"href":285},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","lets everybody through anyway",".",[210,289,291],{"id":290},"_3-can-anyone-download-your-private-files","3. Can anyone download your private files?",[10,293,107,294,111,297,300],{},[73,295,296],{},"yourapp.com\u002F.env",[73,298,299],{},"yourapp.com\u002F.git\u002Fconfig"," in a private window. Both\nshould fail to open.",[10,302,303,304,307,308,311],{},"An ",[73,305,306],{},".env"," file is every key you believed was safely on the server, in a plain\nlist, at a guessable address. A ",[73,309,310],{},".git"," directory is your project's history.\nNeither is meant to be served, and both occasionally are, usually because a\nbuild copied a folder it should not have.",[10,313,314,315,319],{},"This is the rarest thing we find: 8 apps out of 30,749. It is also five seconds\nof work to rule out, and it is\n",[189,316,318],{"href":317},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","where the most damaging leaks come from","\nwhen it happens.",[210,321,323],{"id":322},"_4-will-your-storage-buckets-list-what-is-in-them","4. Will your storage buckets list what is in them?",[10,325,326],{},"In Supabase, open Storage. Read the Public column on each bucket, then open the\npolicies on any bucket holding something that is not meant for everyone.",[10,328,329,330,334],{},"Two different things are going on here and they are easy to run together. A\npublic bucket serves any file whose name somebody already knows. A ",[331,332,333],"em",{},"listable","\nbucket hands over the names, which turns \"somebody would have to guess\" into a\ndirectory of your users' uploads. Our check tests the second one, because that\nis the one that changes what a stranger can actually do.",[10,336,337,338,342],{},"792 apps out of 27,269 had a bucket that listed itself to us without a login.\n",[189,339,341],{"href":340},"\u002Fblog\u002Fsupabase-storage-bucket-public","What a stranger gets from that list"," is\nthe longer version, and the fix is usually one toggle plus one policy.",[28,344,346],{"id":345},"the-five-that-can-wait-until-you-have-users","The five that can wait until you have users",[10,348,349],{},"Headers, source maps, your own API addresses, the certificate and the domain.\nThree of these are usually set by whoever hosts your app, and two of them are\ndates in a calendar.",[10,351,352],{},"None of them hands over a row of your database on its own, which is why they sit\nin the second group. One of the five is worth pulling forward if your app has a\nbackend of its own, and it is flagged below.",[210,354,356],{"id":355},"_5-are-the-browser-safety-headers-switched-on","5. Are the browser safety headers switched on?",[10,358,359],{},"This is the one item on the list with no version you can run from the address\nbar. A scan reads them, or you open your browser's developer tools, look at the\nNetwork tab, click the first request, and read the response headers.",[10,361,362],{},"They are small instructions to the browser: load this page over HTTPS only,\nrefuse to be framed by another site, do not guess at file types. Their absence\ndoes not expose anything by itself. It removes protections that make other\nattacks harder.",[10,364,365,366,370],{},"Almost nobody passes this one and almost nobody can. 30,756 apps out of 30,981\nwere missing at least one, and on a builder subdomain the setting belongs to the\nplatform.\n",[189,367,369],{"href":368},"\u002Fblog\u002Fmissing-security-headers","Whether you can do anything about yours","\ndepends entirely on where your app is hosted.",[210,372,374],{"id":373},"_6-is-your-original-source-code-published","6. Is your original source code published?",[10,376,377],{},"Open your live app, open your browser's developer tools, and look at the Sources\npanel. If your own files are listed there with the code you wrote and the\ncomments you left, the source maps went out with the build.",[10,379,380],{},"A source map is a translation table that turns the compressed file your app\nships back into readable code. Developers use it to debug a live site. Published\nto the internet, it means anyone can read your app the way you wrote it.",[10,382,383,384,388],{},"3,885 apps out of 30,987 published theirs. It is not a leak by itself, and it\nbecomes one when the code contains something you assumed nobody would read.\n",[189,385,387],{"href":386},"\u002Fblog\u002Fsource-maps-exposed-in-production","What a published map exposes"," covers\nthe difference and the build setting that turns it off.",[210,390,392],{"id":391},"_7-do-your-own-api-addresses-answer-a-stranger","7. Do your own API addresses answer a stranger?",[10,394,395],{},"Copy one of your app's own API addresses out of the Network tab, then open it in\na private window where you are not signed in. Look at what comes back.",[10,397,398],{},"This is the item to pull forward if your app has a backend of its own, because\nanything an address hands to a request with no login is public, whatever the\npage in front of it looks like. 3,852 apps out of 30,926 had at least one.",[10,400,401,402,406],{},"The related setting is CORS, which decides which other websites may call your\napp from a visitor's browser. A wildcard there is often fine and occasionally is\nnot, and\n",[189,403,405],{"href":404},"\u002Fblog\u002Fcors-wildcard-security-risk","which of the two you have"," is worth reading\nbefore you change anything.",[210,408,410],{"id":409},"_8-is-your-certificate-about-to-expire","8. Is your certificate about to expire?",[10,412,413],{},"Click the padlock in the address bar, open the certificate, and read the \"Valid\nuntil\" date.",[10,415,416],{},"Almost every host renews these automatically and almost every one of them works.\n32 apps out of 30,851 had a certificate expired, expiring or untrusted. When it\ndoes fail, visitors get a full-page browser warning telling them your site is\nunsafe, and most of them leave.",[210,418,420],{"id":419},"_9-is-your-domain-renewed","9. Is your domain renewed?",[10,422,423],{},"Sign in to your registrar, read the expiry date, and check that auto-renew is on\nand the card behind it has not expired.",[10,425,426],{},"This is the least technical item on the list and the only one that can remove\nyour app from the internet completely. 55 apps out of 30,980 had a domain\nexpired or expiring. A lapsed name can also be registered by somebody else,\nalong with every link anyone ever made to it.",[36,428],{"alt":429,"caption":430,"src":431},"The same nine check icons in two columns. On the left they are ordered by how often a scan finds each one; on the right by the order this article works through them. Curved lines connect each icon to itself and cross in the middle, with four of them drawn in accent.","Left: how often we found each one across 30,998 apps. Right: the order this list works in. The two disagree, which is why the commonest finding on the internet is not the first thing to do.","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Ftwo-orders-of-nine-1600x790.png",[28,433,435],{"id":434},"what-other-checklists-carry-that-is-not-a-security-check","What other checklists carry that is not a security check",[10,437,438],{},"Backups, error monitoring, dead code and password advice. The first of those is\nthe one most likely to cost you something, and it is not a security check,\nbecause nothing outside your app can tell whether you have one.",[10,440,441],{},"That is the honest reason it is absent from the nine. A scanner reads your live\nsite; a backup is a copy of your database sitting somewhere else, and no amount\nof looking at your app from outside can say whether it exists, whether it is\ncurrent, or whether it would restore. It still belongs on your list. It belongs\non the kind of list you keep rather than the kind you run.",[10,443,444,445,449],{},"Supabase's own backups depend on your plan and stay inside your Supabase\naccount, which is fine until the problem is the account.\n",[189,446,448],{"href":447},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","The three routes to a copy you actually hold","\nsets out what each one covers.",[10,451,452,453,457,458,461,462,287],{},"If you would rather it happened without you, that is what\n",[189,454,456],{"href":455},"\u002Fpricing","Reeve Care"," does. It takes a copy of your Supabase database on a\nschedule set by the plan you are on, every night on the entry tier and up to\nfour times a day on the top one, reads each copy back before it counts as a\nbackup, and keeps it somewhere Supabase cannot reach. How far back you can go is\nset the same way. Restoring is a button, and it takes a snapshot of the\ncurrent state before it starts, so pressing it in a panic cannot destroy the\nthing you were trying to save. Uploaded files come too, once you connect a\nStorage credential, which is asked for separately because it is the one key we\nhold that can write: Supabase issues no read-only key for files. Care starts at\n$49 a month for one app, and that is a list price, so the\n",[189,459,460],{"href":455},"pricing page"," is sometimes below the figure here and never above it.\nHow a copy is taken, checked and put back is drawn step by step on the\n",[189,463,465],{"href":464},"\u002Fsupabase-backups","Supabase backups page",[10,467,468],{},"The rest of what those lists carry is real work and not this work. Error\nmonitoring tells you when your app breaks, which is operations. \"Remove unused\ndependencies\" is housekeeping. \"Use strong passwords\" is true of everything you\nhave ever logged into.",[28,470,472],{"id":471},"how-often-should-i-run-this-again","How often should I run this again?",[10,474,475],{},"After every deploy that touched your database rules, your keys or your build\nsettings. If that sounds like most deploys, it is, which is the real problem\nwith a checklist you run once.",[10,477,478],{},"The walkaround happens before every flight for exactly this reason. Row Level\nSecurity gets switched off at midnight to make a page load and nobody switches\nit back. A key gets pasted into the frontend to ship a feature before a demo. A\nbucket gets opened for one upload and stays open. Every one of those is a normal\nTuesday, and each is enough to turn a clean result into a serious one.",[10,480,481,484],{},[189,482,483],{"href":455},"Reeve Monitor"," exists for that gap. It re-runs all nine checks every\nhour on up to three apps, watches whether the app is up every 60 seconds, tells\nyou the day a result changes rather than waiting for you to look, and sends a\nmonthly report in plain language. It is $12 a month at list, with seven days\nfree before it charges you, and the pricing page is sometimes below the figure\nhere and never above it. Monitor watches and nothing more. Backups are the Care\nplan above it, and Care holds a copy of a Supabase database only.",[28,486,488],{"id":487},"what-none-of-this-proves","What none of this proves",[10,490,491],{},"That your app is secure. Nine checks coming back clean means nine questions\nasked from outside came back clean on the day you asked them.",[10,493,494],{},"Four things stay invisible to every item on this list, because none of them ever\nleaves your server. Your server code, including the database functions and edge\nfunctions nobody outside can read. The environment variables you kept out of the\nbrowser, which is exactly where they belong and also why a scan cannot confirm\nthey are stored properly. Your version history, where a key you committed in\nMarch and removed in April is still sitting. And your app's own logic, such as\nwhether one signed-in user can open another user's order by changing a number in\nthe address.",[496,497,499],"callout",{"type":498},"warn",[10,500,501,504],{},[17,502,503],{},"An automated external check is not an audit."," The absence of a finding is not\na guarantee, and nothing on this page is a verdict on your app as a whole. If\nyour app takes payments or holds anyone's health or financial records, a\npenetration test by a person is a different exercise and eventually the right\none.",[10,506,507,511],{},[189,508,510],{"href":509},"\u002Fblog\u002Fvibe-coding-security-scanner","What a URL scan can and cannot see"," goes\nthrough that boundary properly, including the three tools that read different\nthings and where each one is blind.",[28,513,515],{"id":514},"what-to-do-right-now","What to do right now",[517,518,519],"key-takeaways",{},[520,521,522,540,543,546,549],"ul",{},[523,524,525,526,76,528,76,530,111,532,534,535,111,537,539],"li",{},"Run the four urgent ones in order: search your project for ",[73,527,75],{},[73,529,79],{},[73,531,82],{},[73,533,85],{},"; open Advisors, then Security, in Supabase; open ",[73,536,110],{},[73,538,114],{}," in a private window; read the Public column and the policies in Storage.",[523,541,542],{},"If you find a secret key, rotate it before you remove it. Deleting the key from your code leaves the old value working, and it is still in your version history and in anyone's cached copy of your site.",[523,544,545],{},"Work the remaining five when nothing is on fire. Three of them belong to your host, and the two dates belong in your calendar.",[523,547,548],{},"Put a backup somewhere your Supabase account cannot delete it, then restore it once so that you know it works.",[523,550,551],{},"Run the whole list again after any deploy that touched your database, your keys or your build settings.",[10,553,554,555,559,560,564],{},"If your app keeps its data in Supabase, the version of all this written around\nthat one stack is the ",[189,556,558],{"href":557},"\u002Fis-your-supabase-app-safe","Supabase apps guide",". And if\nyou want something to tick rather than to read, the\n",[189,561,563],{"href":562},"\u002Fchecklist","10-minute security checklist"," is the interactive one.",{"title":566,"searchDepth":567,"depth":567,"links":568},"",3,[569,571,577,584,585,586,587],{"id":30,"depth":570,"text":31},2,{"id":196,"depth":570,"text":197,"children":572},[573,574,575,576],{"id":212,"depth":567,"text":213},{"id":262,"depth":567,"text":263},{"id":290,"depth":567,"text":291},{"id":322,"depth":567,"text":323},{"id":345,"depth":570,"text":346,"children":578},[579,580,581,582,583],{"id":355,"depth":567,"text":356},{"id":373,"depth":567,"text":374},{"id":391,"depth":567,"text":392},{"id":409,"depth":567,"text":410},{"id":419,"depth":567,"text":420},{"id":434,"depth":570,"text":435},{"id":471,"depth":570,"text":472},{"id":487,"depth":570,"text":488},{"id":514,"depth":570,"text":515},"Security basics","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcover-1200x630.png","A list of nine ruled rows, each with an empty box beside it, none of them ticked yet.","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.",false,"md",[595,598,601,604,607,610],{"q":596,"a":597},"What should I check before launching a vibe-coded app?","Four things, in this order: whether a secret key reached the code your app ships to browsers, whether your database tables answer a request with nobody signed in, whether files like \u002F.env open straight from your live address, and whether your storage buckets will list what your users uploaded. Those four are where a stranger gets your data or your money. The other five items on the list are worth doing and none of them is a reason to delay a launch.",{"q":599,"a":600},"How long does this take?","Three of the four urgent ones are one look each once you know where to look: a search of your own project for four key prefixes, the Advisors page in Supabase, and two addresses typed into a private window. The database one takes as long as you have tables, because you read the policy on each. Our free scan runs all nine from outside in about 20 seconds with no account, which is the honest shortcut for a first pass.",{"q":602,"a":603},"Do I need a developer for any of it?","Not for the tests. Every one of the nine is a page in a dashboard, an address in your browser, or a search of your own project. Some of the fixes are a different matter: moving work that needed a secret key onto a server is real development, and writing a row-level security policy that lets the right people in is the part most owners hand to somebody. Running the tests yourself is still worth it, because what you find decides what you ask for.",{"q":605,"a":606},"What is the single most important one?","Whether your database tables answer a stranger. It is the one where the data at stake belongs to your users rather than to you, and it is the commonest serious finding we see. Of the apps whose Supabase project answered our scan between 12 and 14 August 2026, 57% had at least one table handing rows to a request with nobody signed in. A secret key in the bundle does more damage when it happens, and it happens far less often.",{"q":608,"a":609},"How often should I re-check?","After any deploy that touched your database rules, your keys or your build settings, and monthly otherwise. A result describes the app that was live when you asked. Row-level security gets switched off to make a page load and stays off, a key gets pasted in to ship a feature tonight, a bucket gets opened for one upload. None of those announces itself.",{"q":611,"a":612},"Does passing this mean my app is secure?","No. It means nine questions asked from outside came back clean on the day you asked them. An automated external check is not an audit, and the absence of a finding is not a guarantee. Everything running on your server is invisible to all nine: your server code, the keys you kept out of the browser, the key you committed in March and deleted in April, and whether one signed-in user can open another user's order by changing a number in the address.","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",[615,616,617,618,619,620,621,622,623],"vibe coding security checklist","vibe coded app security checklist","AI app security checklist","lovable security checklist","bolt security checklist before launch","launch checklist for AI built app","pre-launch security check","is my app ready to launch security","vibe coding production checklist",{},true,"The vibe coding security checklist","\u002Fblog\u002Fvibe-coded-app-security-checklist","2026-09-20",{"title":5,"description":591},"blog\u002Fvibe-coded-app-security-checklist",[632,633,634],"A vibe coding security checklist is only worth having if you can finish it. This one has nine items, because nine is how many things about a live app anyone can verify from outside it.","Four of them decide whether a stranger can reach your data or your money. Run those four before you share the URL with anybody.","The other five are settings and dates. They belong on the list, and none of them hands over a row of your database on its own.","ZPBY3nzmKSDfTDjE61OQapM3RddEEBS3kvArxJBK00s",[637,644,650,656,657,663,669,675,681,687,693,699,705,711,716,721,726,732,738,743,748,754,759,765,771,777,783,789,795,800,806,812,817,823,829,835,839,845,851,856,861,866],{"path":638,"title":639,"description":640,"published":641,"category":642,"image":643,"draft":592},"\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":645,"title":646,"description":647,"published":648,"category":588,"image":649,"draft":592},"\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":651,"title":652,"description":653,"published":654,"category":588,"image":655,"draft":592},"\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":627,"title":5,"description":591,"published":628,"category":588,"image":613,"draft":592},{"path":658,"title":659,"description":660,"published":661,"category":588,"image":662,"draft":592},"\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":664,"title":665,"description":666,"published":667,"category":588,"image":668,"draft":592},"\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":670,"title":671,"description":672,"published":673,"category":588,"image":674,"draft":592},"\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":676,"title":677,"description":678,"published":679,"category":588,"image":680,"draft":592},"\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":682,"title":683,"description":684,"published":685,"category":588,"image":686,"draft":592},"\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":688,"title":689,"description":690,"published":691,"category":642,"image":692,"draft":592},"\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":694,"title":695,"description":696,"published":697,"category":642,"image":698,"draft":592},"\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":700,"title":701,"description":702,"published":703,"category":642,"image":704,"draft":592},"\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":706,"title":707,"description":708,"published":709,"category":588,"image":710,"draft":592},"\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":280,"title":712,"description":713,"published":714,"category":588,"image":715,"draft":592},"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":269,"title":717,"description":718,"published":719,"category":588,"image":720,"draft":592},"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":257,"title":722,"description":723,"published":724,"category":588,"image":725,"draft":592},"How to rotate a leaked Supabase service_role key","Supabase says fix the leak first. Other guides say rotate now. Which is right depends on where your service_role key leaked.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":727,"title":728,"description":729,"published":730,"category":588,"image":731,"draft":592},"\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":733,"title":734,"description":735,"published":736,"category":588,"image":737,"draft":592},"\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":509,"title":739,"description":740,"published":741,"category":588,"image":742,"draft":592},"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":368,"title":744,"description":745,"published":746,"category":588,"image":747,"draft":592},"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":749,"title":750,"description":751,"published":752,"category":588,"image":753,"draft":592},"\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":317,"title":755,"description":756,"published":757,"category":588,"image":758,"draft":592},"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":760,"title":761,"description":762,"published":763,"category":642,"image":764,"draft":592},"\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":766,"title":767,"description":768,"published":769,"category":588,"image":770,"draft":592},"\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":772,"title":773,"description":774,"published":775,"category":642,"image":776,"draft":592},"\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":778,"title":779,"description":780,"published":781,"category":588,"image":782,"draft":592},"\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":784,"title":785,"description":786,"published":787,"category":588,"image":788,"draft":592},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","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":790,"title":791,"description":792,"published":793,"category":588,"image":794,"draft":592},"\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":404,"title":796,"description":797,"published":798,"category":588,"image":799,"draft":592},"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":801,"title":802,"description":803,"published":804,"category":642,"image":805,"draft":592},"\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":807,"title":808,"description":809,"published":810,"category":642,"image":811,"draft":592},"\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":340,"title":813,"description":814,"published":815,"category":588,"image":816,"draft":592},"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":818,"title":819,"description":820,"published":821,"category":588,"image":822,"draft":592},"\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":824,"title":825,"description":826,"published":827,"category":642,"image":828,"draft":592},"\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":830,"title":831,"description":832,"published":833,"category":588,"image":834,"draft":592},"\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":386,"title":836,"description":837,"published":833,"category":588,"image":838,"draft":592},"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":840,"title":841,"description":842,"published":843,"category":588,"image":844,"draft":592},"\u002Fblog\u002Fsupabase-new-api-keys","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":846,"title":847,"description":848,"published":849,"category":642,"image":850,"draft":592},"\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":285,"title":852,"description":853,"published":854,"category":588,"image":855,"draft":592},"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":857,"title":858,"description":859,"published":854,"category":642,"image":860,"draft":592},"\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":447,"title":862,"description":863,"published":864,"category":642,"image":865,"draft":592},"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":239,"title":867,"description":868,"published":864,"category":588,"image":869,"draft":592},"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]