← Stack guides

Replit

Security for your Replit app

Replit gives you editor, database and hosting in one place, and with the Agent you can ship without touching the terminal. The risk: secrets that end up in the code, public Repls that expose your files, and open services without headers. Scan it before you share the link.

Typical risks in Replit

Secrets in the code instead of in Secrets

Replit has a Secrets manager, but it is easy to end up with the key written in the code or a config file. If the Repl is public or gets deployed, that key leaks.

Public Repls that expose your files

A public Repl lets anyone see all the project code and files, including forgotten .env files or backups. Check what is visible before assuming it is private.

Open services without headers

A Replit deployment exposes your app on a public URL with no security headers. If you also leave endpoints or ports unprotected, they are within anyone's reach.

"Replit security" is two things worth keeping apart. The first is the Repl and its deployment: where secrets live, who sees your files, which URL is public and which port is exposed. The second is the code Replit Agent generates, usually an Express server with React and a Postgres database, which ships with the classic flaws of a backend written in a hurry. This guide covers both, with a block for the file the Agent reads on every request, a review prompt before deploying and the checks from outside.

Part 1: securing your Repl and your deployment

Secrets: the Secrets tab, not the code

Replit has a secrets manager that stores variables encrypted and exposes them to the process as environment variables, without them appearing in any file. It is the only right place for API keys, the database connection string and the session secret. The usual mistake is that the Agent, or you in a hurry, writes them into a .env, a config.json or straight into the code. Those files are part of the Repl: they are visible in a public Repl, copied on fork and deployed.

Public Repls and the development URL

A public Repl shows all its files to anyone, including the ones you forgot: backups, an old .env, data exports. Before making it public, review the whole tree. And while the Repl is running, the .replit.dev development URL answers whoever has it; it is not a private environment, it is a server on the internet with your test data.

Deployments

Deployment publishes the app on a .replit.app subdomain or your domain, with automatic TLS. The deployment's environment variables are configured separately from development's, so check that production does not point at the test database. Only the port you declare is exposed, but everything that port serves is public: API routes, static files and whatever the server returns by mistake. Replit adds no security headers; your server sets them.

Built-in database and authentication

The built-in Postgres database hands you its connection string as a secret; never copy it into a file. If you use Replit Auth, Replit manages the session and your code receives the already identified user, but every route still has to check that there is a session and that this user may do what they ask.

Part 2: the flaws the Agent puts into your code

  • Secrets in files. The OpenAI key or the Postgres string in .env, in a constant or in a config.json served as static.
  • API routes without authentication. The dashboard checks the session in React; /api/users answers anyone.
  • Static folders that are too wide. express.static pointing at the project root serves package.json, .replit, the server code and any forgotten file. And without an index.html, some servers list the directory.
  • Debug and seed routes. /api/debug, /api/seed, /api/reset created for testing and deployed.
  • Open CORS with credentials. cors() with no options plus session cookies: any website acts on behalf of your users.
  • SQL queries by concatenation. A string built with what arrives from the form instead of parameters.
  • File uploads to disk served as is. Any user uploads a file and any visitor downloads it by name.
  • No rate limit, no headers. An endpoint that calls a paid model with no cap, and not one security header.

A block so the Agent always applies it

Replit Agent reads your project's replit.md file as permanent context. Add this section:

## Security rules
- Keys, the database string and the session secret are read from process.env and live in the Secrets tab. Never in .env, config.json or the code.
- Every API route that reads or writes data checks the user's session and permissions on the server. Checks in React do not count.
- express.static only serves the frontend build folder or public/, never the project root.
- No debug, seed or reset routes in production.
- CORS with an explicit list of origins; never the wildcard with credentials.
- All SQL queries use parameters. All form input is validated on the server.
- Uploaded files are stored outside the public folder and served only after checking permissions.
- Security headers with helmet and a rate limit on routes that cost money.

And the headers in Express, in two lines:

import helmet from 'helmet';
app.use(helmet());
app.use(helmet.hsts({ maxAge: 63072000, includeSubDomains: true, preload: true }));

A review prompt before you deploy

Review the security of this project and do not change anything yet. Answer with a list:
1. Keys, connection strings or secrets written in files or in the code, with file and line.
2. API routes that read or write data without checking the session, and debug, seed or reset routes.
3. Folders served as static and which files they expose.
4. CORS and session cookie configuration.
5. SQL queries built by concatenation and unvalidated input.
6. Where uploaded files are stored and how they are served.
7. Whether security headers and a rate limit exist.
For each point, propose the exact change and wait for my confirmation.

Check the result from the outside

curl -sI https://yourdomain.com | grep -iE "strict-transport|x-frame|x-content-type|content-security"
for p in .env .replit package.json config.json .git/config server.js uploads/; do printf "%-14s " "$p"; curl -s -o /dev/null -w "%{http_code}\n" "https://yourdomain.com/$p"; done
curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/api/users

Expected: headers present, 404 on the whole file list and a 401 or 403 on the API route without a session. A 200 on package.json or .replit means you are serving the project root. Scanaris runs these checks and about forty more in 30 seconds: it looks for exposed files and directory listings, endpoints that answer without a session, secrets in the JavaScript, headers, CORS, cookies and TLS, and gives you a fix prompt for each failure to paste into the Agent chat. And it can rescan every day, because a regeneration can bring back a flaw you had already fixed.

Frequently asked questions

Are Secrets tab values visible in a public Repl?

No, secrets are not shown and are not copied on fork. What is visible is everything else: files, code and any key written in them instead of in Secrets.

Is the development URL private?

No. While the Repl runs, it answers anyone who has the link. Do not use it with real data or share it thinking only you can see it.

Does Replit set security headers on deployments?

No. It provides TLS and the domain, but the headers are sent by your server. With Express, helmet adds them in two lines; with other frameworks, their equivalent.

Related checks

Does your Replit app pass these checks?

Scan it free and get a fix prompt for every issue we find.

Scan my site free