Replit app security: what Replit handles for you, and the six holes Agent-built apps still ship with
Replit is a trusted, mature platform: your code is yours, secrets have a proper home, and Replit now scans projects for vulnerabilities itself. None of that stops Replit Agent from building an app whose Express route forgets to check who is calling. This is the list of what goes wrong in apps built on Replit, how to check each one in a minute, and the prompt that fixes it.
Is Replit a trusted app? Does Replit own your code?
Replit is a trusted platform used by millions of developers and by companies, with a published security program, a security checklist for builders, and a vulnerability scanner built into the product. You own the code you write on Replit; their terms are explicit that your work is yours. The platform is not the risk. The app you describe to Replit Agent can be.
That distinction is the whole post. Replit gives you secure building blocks: a Secrets pane that keeps keys out of code, Replit Auth for sign-in, hosted Postgres, HTTPS on every replit.app address. Agent assembles those blocks fast, and sometimes puts a block in the wrong place.
What Replit handles for you
- Secrets. Values in the Secrets pane become environment variables on the server and never touch the code or the repo. Used correctly, this is the whole answer to leaked keys.
- HTTPS on every
replit.appaddress and on custom domains. - Replit Auth, a sign-in system you do not have to build, so passwords are not your problem.
- Vulnerability scanning inside the workspace (Replit's Security Center and its automatic protections) that catches a good share of the common mistakes. Run it, read it, and then check from the outside too.
- A hosted database (Postgres) that is only reachable from your server code, not from the browser.
The six holes Replit Agent apps ship with
Agent-built web apps usually share a shape: a React front end built with Vite, an Express server, Postgres (Replit's own, or Supabase or Firebase if you asked for them). Each layer has a characteristic mistake.
1. A secret in a VITE_ variable instead of Secrets
Vite copies every variable starting with VITE_ into the JavaScript the browser downloads. When Agent needs the front end to talk to OpenAI, it sometimes creates VITE_OPENAI_API_KEY and the feature works. The key is now in every visitor's browser. Secrets without the prefix stay on the server, which is where the OpenAI call should be.
Check: open Secrets. Any entry starting with VITE_ whose value is a secret is a leak. Then open the published app, press F12, Network, reload, click the biggest .js file and search for sk-. The full response plan is in what to do when an API key is in your front-end JavaScript.
2. A key pasted straight into a file
Less common on Replit than elsewhere, because Secrets exists, but it happens when someone pastes a key into the chat and Agent puts it where it was pointed. If the project is public, or exported to GitHub, the key is public.
Check: use the workspace search for sk-, sk_live, whsec_ and password. Any hit outside Secrets is a problem. Rotate first, then move it.
3. An Express route that never checks who is calling
This is the Replit-specific one. Agent writes clean Express routes, and it writes the sign-in flow, and it frequently forgets to connect them: app.delete("/api/posts/:id") deletes the post for whoever asks. The front end only shows the delete button to the owner, so it looks fine. The server does not care about buttons.
Check: open the server file (often server/routes.ts). For every route that creates, changes or deletes data, look for a check of the signed-in user before the database call. If a route reads req.params.id and goes straight to the query, it is open.
Security fix: several Express routes under /api change data without checking who is signed in.
Add authentication middleware that rejects requests with no valid session (401), and apply it to every route that creates, updates or deletes data. For routes that act on a specific record (for example DELETE /api/posts/:id), also check that the record belongs to the signed-in user and return 403 if it does not.
Do not change the UI. List the routes you protected.
4. Admin decided in the browser
An isAdmin flag in React state or localStorage, read to show the admin panel. Anyone can set it in the developer tools. The admin panel's routes then need their own server-side check (see 3), or the flag is the only lock on the door.
Check: search the client folder for isAdmin, role and localStorage. Every admin decision needs a matching check in the server routes.
5. CORS open to every website, with credentials
When the front end and the API are served from different addresses, Agent reaches for the cors package, and the configuration that makes the error go away is cors({ origin: true, credentials: true }). That tells browsers any website may call your API with your users' cookies attached. A page someone visits elsewhere can then read their data from your app.
Check: search the server for cors(. The origin should be your app's actual address (or a short list), not true or *, whenever credentials is on.
6. What the GitHub export carries
Replit can push your project to GitHub. If a .env file exists in the project (some templates create one), and it is not in .gitignore, it goes along. Secrets from the Secrets pane do not, which is one more reason to use it.
Check: if you have connected GitHub, open the repo and look for .env at the top level. If it is there, rotate every value in it.
The six on one screen
| Hole | Where to look | Fix in one line |
|---|---|---|
| Secret in a VITE_ variable | Secrets pane | drop the prefix, call the provider from an Express route |
| Key pasted into a file | workspace search for sk- | rotate, move to Secrets |
| Route without an auth check | server/routes.ts | auth middleware plus an ownership check |
| Admin decided in the browser | client, isAdmin / localStorage | check the role on the server for every admin route |
| cors({ origin: true, credentials: true }) | server, cors( | set origin to your app's address |
| .env in the GitHub export | the repo on GitHub | rotate, add .env to .gitignore |
Questions people ask
Is Replit secure for building a real product?
Yes. Replit's platform security is solid and its building blocks (Secrets, Auth, hosted Postgres) are the right ones. The app Replit Agent produces still needs the checks above before customers use it, the same as an app from any AI builder.
Does Replit own the code I write?
No. You own the code you create on Replit. Replit's terms grant them the rights needed to host and run it, not ownership. If your Repl is public, anyone can view and fork the code, so keep secrets in the Secrets pane rather than in files.
Are Replit Secrets really hidden from the browser?
Yes, as long as the name does not start with VITE_. Secrets are environment variables available to your server code. Vite copies variables with the VITE_ prefix into the browser bundle, which is the one way a Secret ends up public.
Does VibeProtect scan any Replit app?
No. Only apps whose owner has verified them, by having Agent add a small file at /.well-known/vibeprotect.txt to the public folder. We never scan an app for someone who does not own it.