[{"data":1,"prerenderedAt":584},["ShallowReactive",2],{"blog-en-replit-secrets-explained":3,"blog-index-en":342},{"id":4,"title":5,"body":6,"category":299,"cover":300,"coverAlt":301,"description":302,"draft":303,"extension":304,"faq":305,"image":320,"keywords":321,"meta":328,"navigation":329,"ogTitle":330,"path":331,"published":332,"seo":333,"stem":334,"tldr":335,"updated":340,"__hash__":341},"blog_en\u002Fblog\u002Freplit-secrets-explained.md","How to use secrets in Replit, and what still gets published",{"type":7,"value":8,"toc":288},"minimark",[9,13,21,24,33,38,41,80,83,90,94,97,100,103,107,110,113,116,122,136,147,160,167,171,174,184,190,195,205,208,212,215,218,221,232,238,246,250,276],[10,11,12],"p",{},"Somewhere between building your app and publishing it, Replit told you to stop\nputting your API key in the code. So you looked up how to use secrets in Replit,\nmoved the key into the Secrets tool, and the warning went away. Then something\ntold you the key is still visible in your published app, and both of those\nthings seem to be true at the same time.",[10,14,15,16,20],{},"They are. Here is the part most advice about this leaves out: ",[17,18,19],"strong",{},"the Secrets tool\ndecides where a value is kept. Your code decides where it is carried."," Those are\ntwo separate questions, and only the first one has anything to do with the tool.",[10,22,23],{},"Replit is where this bites hardest, because the half of your app that runs on\nReplit's machine and the half that runs on your visitor's laptop sit in the same\nproject, often in adjacent files. Nothing in the editor draws a line between\nthem.",[10,25,26,27,32],{},"Between 12 and 14 August 2026 we ran the same nine external checks over 30,998\nlive apps, of which 3,042 were published on Replit. In 219 of those Replit apps\nsomething key-shaped was sitting in the code a visitor downloads. Across the\nwhole sample most of what that check finds is a Google key, which is usually\nfine once it has been restricted. The ones that are not fine are the ones a\nsecrets manager was supposed to prevent. The full numbers are in\n",[28,29,31],"a",{"href":30},"\u002Fresearch\u002Fvibe-coded-app-security-2026","our scan report",".",[34,35,37],"h2",{"id":36},"how-do-i-use-secrets-in-replit","How do I use secrets in Replit?",[10,39,40],{},"Open the Secrets tool, add a name and a value, and read the value back in your\ncode as an environment variable. It takes about a minute.",[42,43,44,52,64,67,77],"ol",{},[45,46,47,48,51],"li",{},"In your project, open ",[17,49,50],{},"Secrets",". It is in the tools list, and searching the\ntool pane for the word finds it.",[45,53,54,55,58,59,63],{},"Choose ",[17,56,57],{},"+ New secret",". Give it a name in capitals with underscores, like\n",[60,61,62],"code",{},"OPENAI_API_KEY",". That name is what your code will use, so it matters more\nthan it looks.",[45,65,66],{},"Paste the value into the second field and save. Replit encrypts it and keeps\nit outside your project files.",[45,68,69,70,73,74,32],{},"Read it in your code. In JavaScript that is ",[60,71,72],{},"process.env.OPENAI_API_KEY",", and\nin Python it is ",[60,75,76],{},"os.getenv(\"OPENAI_API_KEY\")",[45,78,79],{},"Go back and delete the value from wherever it was before.",[10,81,82],{},"Step five is the one people skip, and it is the one that decides whether any of\nthis helped. Adding a secret does not remove the copy you already had. A key\npasted into a file last week is still in that file, still in your project\nhistory, and still inside every copy of your app that has been published since.",[10,84,85,86,89],{},"A ",[60,87,88],{},".env"," file does the same job as the Secrets tool, with one difference that\nmatters: it is a file, so it travels with the project when somebody forks it or\nconnects it to a repository.",[34,91,93],{"id":92},"are-replit-secrets-safe","Are Replit Secrets safe?",[10,95,96],{},"For the job they do, yes. The value is encrypted, it is kept out of your source,\nand the three commonest ways a key gets away from someone are all closed by\nthat: you share your project with a collaborator, you connect it to a\nrepository, or somebody watches you work.",[10,98,99],{},"Think of it as a locked drawer. Anything in the drawer is out of sight of a\nperson reading your files. What the drawer cannot decide is what your app does\nwith the contents once your own code has opened it and walked off.",[10,101,102],{},"And a published Replit app walks off with quite a lot. Every visitor who loads\nyour site is sent the entire front half of it, because a browser cannot draw a\npage it was not sent. If the code that opens the drawer is code that gets sent\nto visitors, the value it took out travels with it.",[34,104,106],{"id":105},"which-half-of-your-app-reads-the-key","Which half of your app reads the key?",[10,108,109],{},"The half that runs on Replit's machine can read a secret safely. The half that\nruns in your visitor's browser cannot, and the usual way of making it work is\nalso the way the key becomes public.",[10,111,112],{},"Your server code is the part Replit runs: an Express route, a Python handler, a\nfunction that talks to OpenAI or Stripe and sends your app back an answer. It\nreads a secret, uses it, and the value never leaves the machine.",[10,114,115],{},"Your browser code is everything the visitor's laptop runs. In a React project\nthat is most of what you have been editing. It is compiled into a bundle of\nJavaScript and downloaded, in full, by everyone who opens your site.",[117,118],"diagram",{"alt":119,"caption":120,"src":121},"A padlocked store of values inside a dashed boundary standing for Replit's machine, with two paths out of it. The upper path reaches a server that stays inside the boundary, where the value is still drawn as hidden dots and is ticked. The lower path reaches a browser window marked VITE_, then crosses the boundary and ends at a person holding the same value as a bar anyone can read, crossed.","One drawer, two readers. The value goes wherever the code that opened it goes.","\u002Fblog\u002Freplit-secrets-explained\u002Fwhich-half-reads-it-1600x760.png",[10,123,124,127,128,131,132,135],{},[60,125,126],{},"process.env"," does not exist in a browser, so browser code reading it gets\nnothing at all. To make the value arrive, somebody renames it:\n",[60,129,130],{},"VITE_OPENAI_API_KEY"," in a Vite project, or ",[60,133,134],{},"NEXT_PUBLIC_OPENAI_API_KEY"," in a\nNext.js one. It works immediately, because that prefix is an instruction to the\nbuild tool to write the value into the bundle. Vite's own documentation says so\nin as many words, and warns against putting API keys in one for exactly that\nreason.",[10,137,138,139,142,143,146],{},"So the fastest check in this article is a search. Open your project and look for\n",[60,140,141],{},"VITE_"," and ",[60,144,145],{},"NEXT_PUBLIC_",". Every match is a value that your build tool has been\ntold to publish.",[10,148,149,150,154,155,159],{},"That is correct for some of them. A Supabase publishable key is designed to sit\nin a browser, and so is a Google Maps key with a\n",[28,151,153],{"href":152},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","referrer restriction"," on it. It is\nwrong for anything that spends money or reads a database without asking who is\nknocking, and\n",[28,156,158],{"href":157},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","telling the two apart"," takes\nabout a minute per key.",[10,161,162,163,32],{},"If you would rather see what your published app is handing out before you go\nfile by file, our free scan reads your live site from the outside and tells you\nwhat it can find there. It takes about 20 seconds and needs no account:\n",[28,164,166],{"href":165},"\u002Fsecurity-scanner","scan your app",[34,168,170],{"id":169},"why-is-my-replit-secret-not-working","Why is my Replit secret not working?",[10,172,173],{},"Two reasons, and from where you are sitting they produce the same symptom: an\nempty value and an app that does not work.",[10,175,176,179,180,183],{},[17,177,178],{},"The code reading it runs in the browser."," There is no environment there to\nread, so ",[60,181,182],{},"process.env.YOUR_KEY"," is empty and always will be. This one is not a\nconfiguration problem and no amount of re-adding the secret will move it. The\ncall that needs the key has to move to the server half of your app.",[10,185,186,189],{},[17,187,188],{},"Your published app is running an older version."," Replit keeps two sets of\nvalues, the ones in your workspace and the ones your published app runs on. They\nsynchronise, so a secret you add normally reaches the deployment. What the live\napp is actually using, though, is whatever was there the last time you published\nit. Add a secret afterwards and the running app knows nothing about it until you\npublish again.",[117,191],{"alt":192,"caption":193,"src":194},"Two panes side by side. In the editor pane the padlocked store holds a filled value and the preview beside it is ticked. In the published pane the same store has an empty slot and the live app beside it is crossed, with the word undefined below.","The same name in both places. The live app is running on the values that were there when you last published.","\u002Fblog\u002Freplit-secrets-explained\u002Ftwo-stores-one-name-1600x560.png",[10,196,197,198,201,202,204],{},"Replit's own troubleshooting for an app that works in the editor and breaks when\npublished starts in exactly this place, so it is worth opening the deployment\nsecrets and reading the names before assuming anything is broken. A name spelled\n",[60,199,200],{},"OPENAI_KEY"," in one place and ",[60,203,62],{}," in the other produces the same\nempty value as a missing secret.",[10,206,207],{},"A deploy that fails at midnight is when the shortcut gets taken. Pasting the\nvalue straight into the code unblocks it in seconds, the app comes back, and the\nkey is in your published bundle from that moment on.",[34,209,211],{"id":210},"the-key-is-already-in-my-published-app-what-now","The key is already in my published app. What now?",[10,213,214],{},"Rotate it, before you change any code. In the provider's dashboard, generate a\nnew key and revoke the old one.",[10,216,217],{},"That order matters because rotation is the only step that makes the exposed\nvalue stop working. Editing your code removes it from the current version and\nleaves it in your project history, and it does nothing at all about the copies\nof your bundle that have already been downloaded, cached and crawled. Your app\nbeing small does not help either: automated crawlers read public sites for\nkey-shaped strings continuously, with no idea who you are.",[10,219,220],{},"Then, in this order:",[42,222,223,226,229],{},[45,224,225],{},"Put the new key in Secrets and read it from server code only.",[45,227,228],{},"Move the call that needed it. Anything talking to OpenAI, Anthropic, Stripe\nor your database with an administrative key belongs behind a route your app\ncalls, so the browser asks your server and your server holds the key.",[45,230,231],{},"Check the provider's usage and billing pages for the period the old key was\npublic. Rotation stops what happens next and says nothing about what already\nhappened.",[10,233,234,235,237],{},"Model-provider keys are the ones to check first on Replit. ",[60,236,62],{}," is\nthe example Replit's own documentation reaches for when it shows you how to add\na secret, and there is no publishable variant of an OpenAI or Anthropic key.\nEvery one of them bills your account directly.",[10,239,240,241,245],{},"One more place to look while you are here: if your project publishes\n",[28,242,244],{"href":243},"\u002Fblog\u002Fsource-maps-exposed-in-production","source maps",", a visitor can read that\nbundle as the original files you wrote, with your own variable names still on\nthem.",[34,247,249],{"id":248},"what-to-do-this-week","What to do this week",[251,252,253],"key-takeaways",{},[254,255,256,259,267,270,273],"ul",{},[45,257,258],{},"Move every key into the Secrets tool, then delete the copies you left behind in files. Adding a secret does not remove the old value.",[45,260,261,262,142,264,266],{},"Search your project for ",[60,263,141],{},[60,265,145],{},". Each match is a value your build tool publishes on purpose, and each one needs to be a key that was safe to publish.",[45,268,269],{},"For any key that is not, move the call that uses it to your server half, so the browser asks your app and your app holds the key.",[45,271,272],{},"If a secret reads as empty in the published app but works in the editor, publish again and check the name in your deployment secrets before changing code.",[45,274,275],{},"Rotate anything that has already gone out, at the provider, before you touch the code. Then read the billing page for the weeks it was public.",[10,277,278,279,283,284,32],{},"Do the search first. It takes a minute, it needs nothing installed, and it tells\nyou which of the keys in your project are already public. The\n",[28,280,282],{"href":281},"\u002Fchecklist","10-minute security checklist"," covers the rest of what is worth\nconfirming on a newly launched app, and the plain-language walkthrough for this\nplatform is ",[28,285,287],{"href":286},"\u002Fis-your-replit-app-safe","is your Replit app safe",{"title":289,"searchDepth":290,"depth":290,"links":291},"",3,[292,294,295,296,297,298],{"id":36,"depth":293,"text":37},2,{"id":92,"depth":293,"text":93},{"id":105,"depth":293,"text":106},{"id":169,"depth":293,"text":170},{"id":210,"depth":293,"text":211},{"id":248,"depth":293,"text":249},"Security basics","\u002Fblog\u002Freplit-secrets-explained\u002Fcover-1200x630.png","The Replit logo, an arrow to a padlocked store of hidden values, and another arrow on to the running app that reads from it.","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.",false,"md",[306,308,311,314,317],{"q":93,"a":307},"Yes, for the job they do. Replit encrypts the values and keeps them out of your files, so sharing your project, publishing it to a repository or streaming yourself working on it no longer hands the key to anyone watching. What the tool cannot do is decide where your app carries the value afterwards. A key read by code that runs on Replit stays on Replit. The same key read by code that runs in your visitor's browser is built into what you publish, and storing it in Secrets first changes nothing about that.",{"q":309,"a":310},"Why is my Replit secret undefined?","Two causes, and they look the same from where you are standing. Either the code reading it runs in the browser, where there is no environment to read and process.env has nothing in it, or your published app is running a version that was deployed before you added the secret. For the second, publish again: the values a live app is using are the ones that were there when it last went out.",{"q":312,"a":313},"Can I use a secret in my React frontend on Replit?","You can put a value there, and it will not be secret. React code runs on your visitor's machine, so anything it reads has to be sent to that machine first. Build tools make this explicit with a prefix: Vite only exposes variables beginning VITE_ to browser code, and Next.js only exposes NEXT_PUBLIC_ ones. Adding the prefix is how people make a key work in the frontend, and it is also the moment the key becomes public. Publishable keys belong there. Anything that spends money or reads a database belongs on the server.",{"q":315,"a":316},"Do I need to add my secrets again when I publish?","Usually not, because deployment secrets synchronise with your workspace ones, but the value your live app is using is the one that was present at your last publish. A secret added after that reaches the deployment on the next one. Replit's own troubleshooting for an app that works in the editor and fails when published starts here, so if something went missing at deploy time, open the deployment secrets and check the name is there and spelled the same way.",{"q":318,"a":319},"I pasted an API key into a file before I found the Secrets tool. Is deleting the file enough?","No. Rotate the key at the provider first, which is what actually closes the door, then move the value into Secrets. Deleting a line of code removes it from the current version and not from your project history, and not from any copy of your published app that someone already has. Rotation is the only step that makes the old value stop working, and it usually takes about a minute in the provider dashboard.","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",[322,323,324,325,326,327],"how to use secrets in replit","replit secrets","replit secrets not working","are replit secrets safe","replit environment variables","replit secret",{},true,"How to use secrets in Replit","\u002Fblog\u002Freplit-secrets-explained","2026-08-31",{"title":5,"description":302},"blog\u002Freplit-secrets-explained",[336,337,338,339],"How to use secrets in Replit: open the Secrets tool, add a name and a value, and read it back in your code as an environment variable.","That keeps the key out of your files. It does not keep it out of your published app, because a value your browser code reads is built into what every visitor downloads.","The tell is the name. A variable beginning VITE_ or NEXT_PUBLIC_ was deliberately put in the browser by your build tool.","A secret that reads as empty in the published app usually means the live version was published before you added it. Publish again.","2026-09-21","74KWswBAZnGdVvogRXmBOYuGO57lgCfF8ApPLbbFDV0",[343,350,356,361,367,373,379,385,391,397,403,409,415,421,427,433,439,445,451,457,463,469,475,481,482,488,494,500,506,512,518,524,530,535,541,547,551,557,563,569,574,580],{"path":344,"title":345,"description":346,"published":347,"category":348,"image":349,"draft":303},"\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":351,"title":352,"description":353,"published":354,"category":299,"image":355,"draft":303},"\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":357,"title":358,"description":359,"published":340,"category":299,"image":360,"draft":303},"\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.","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":362,"title":363,"description":364,"published":365,"category":299,"image":366,"draft":303},"\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":368,"title":369,"description":370,"published":371,"category":299,"image":372,"draft":303},"\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":374,"title":375,"description":376,"published":377,"category":299,"image":378,"draft":303},"\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":380,"title":381,"description":382,"published":383,"category":299,"image":384,"draft":303},"\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":386,"title":387,"description":388,"published":389,"category":299,"image":390,"draft":303},"\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":392,"title":393,"description":394,"published":395,"category":299,"image":396,"draft":303},"\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":398,"title":399,"description":400,"published":401,"category":348,"image":402,"draft":303},"\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":404,"title":405,"description":406,"published":407,"category":348,"image":408,"draft":303},"\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":410,"title":411,"description":412,"published":413,"category":348,"image":414,"draft":303},"\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":416,"title":417,"description":418,"published":419,"category":299,"image":420,"draft":303},"\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":422,"title":423,"description":424,"published":425,"category":299,"image":426,"draft":303},"\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":428,"title":429,"description":430,"published":431,"category":299,"image":432,"draft":303},"\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":434,"title":435,"description":436,"published":437,"category":299,"image":438,"draft":303},"\u002Fblog\u002Frotate-supabase-service-role-key","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":440,"title":441,"description":442,"published":443,"category":299,"image":444,"draft":303},"\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":446,"title":447,"description":448,"published":449,"category":299,"image":450,"draft":303},"\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":452,"title":453,"description":454,"published":455,"category":299,"image":456,"draft":303},"\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":458,"title":459,"description":460,"published":461,"category":299,"image":462,"draft":303},"\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":464,"title":465,"description":466,"published":467,"category":299,"image":468,"draft":303},"\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":470,"title":471,"description":472,"published":473,"category":299,"image":474,"draft":303},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","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":476,"title":477,"description":478,"published":479,"category":348,"image":480,"draft":303},"\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":331,"title":5,"description":302,"published":332,"category":299,"image":320,"draft":303},{"path":483,"title":484,"description":485,"published":486,"category":348,"image":487,"draft":303},"\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":489,"title":490,"description":491,"published":492,"category":299,"image":493,"draft":303},"\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":495,"title":496,"description":497,"published":498,"category":299,"image":499,"draft":303},"\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":501,"title":502,"description":503,"published":504,"category":299,"image":505,"draft":303},"\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":507,"title":508,"description":509,"published":510,"category":299,"image":511,"draft":303},"\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":513,"title":514,"description":515,"published":516,"category":348,"image":517,"draft":303},"\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":519,"title":520,"description":521,"published":522,"category":348,"image":523,"draft":303},"\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":525,"title":526,"description":527,"published":528,"category":299,"image":529,"draft":303},"\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":152,"title":531,"description":532,"published":533,"category":299,"image":534,"draft":303},"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":536,"title":537,"description":538,"published":539,"category":348,"image":540,"draft":303},"\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":542,"title":543,"description":544,"published":545,"category":299,"image":546,"draft":303},"\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":243,"title":548,"description":549,"published":545,"category":299,"image":550,"draft":303},"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":552,"title":553,"description":554,"published":555,"category":299,"image":556,"draft":303},"\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":558,"title":559,"description":560,"published":561,"category":348,"image":562,"draft":303},"\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":564,"title":565,"description":566,"published":567,"category":299,"image":568,"draft":303},"\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":570,"title":571,"description":572,"published":567,"category":348,"image":573,"draft":303},"\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":575,"title":576,"description":577,"published":578,"category":348,"image":579,"draft":303},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","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":157,"title":581,"description":582,"published":578,"category":299,"image":583,"draft":303},"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]