Is your Replit app leaking?

On Replit your app is a real server, which means it also ships the mistakes of a real server: a wide-open CORS line, an .env next to the static files, a version banner on every response. Paste the address and check.

What a Replit app ships with

The five things that go wrong

  1. A .env served as a file. When the server does express.static on the project root, /.env, /.git/HEAD, and config.json come with it. The scan asks for each and confirms by content.
  2. CORS copied from a tutorial. app.use(cors()) with credentials, or an Origin header echoed back, lets any website call the API with a visitor's cookies.
  3. No security headers. Express sends none by default. A four-line middleware (or the helmet package) fixes the common ones.
  4. Version banners. X-Powered-By: Express and Server: nginx/1.18 tell an attacker exactly what to look up. One line turns them off.
  5. Plain HTTP on a custom domain. Replit's own domains redirect to HTTPS; a custom domain behind your own proxy might not.

How to fix them

Security headers and no version banner in Express

app.disable("x-powered-by");
app.use((req, res, next) => {
  res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("X-Frame-Options", "DENY");
  res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
  next();
});

Never serve dotfiles, and keep static files in their own folder

app.use((req, res, next) => {
  if (/^\/\.(?!well-known)/.test(req.path)) return res.status(404).end();
  next();
});
app.use(express.static("public", { index: "index.html" })); // not the project root

CORS from a fixed list

import cors from "cors";
const allowed = ["https://your-app.com"];
app.use(cors({
  origin: (origin, done) => done(null, !origin || allowed.includes(origin)),
  credentials: true,
}));

Every finding in a scan comes with the exact lines for your host and framework, opened for the one it detected.

Questions people ask

Replit Secrets or .env?
Secrets. They are injected as environment variables and never sit in a file the server could serve or Git could commit. If a .env exists, add it to .gitignore and make sure express.static does not point at its folder.
Does the scanner test my API routes?
It reads the routes your front-end names (fetch('/api/...')), sends each a request from a made-up origin, and reports the ones that answer with that origin allowed plus credentials. Nothing is written.
My app uses Flask, not Express. Do the fixes apply?
The findings are the same; the lines differ. Flask-Talisman sets the headers, flask-cors takes an origins list, and the dotfile rule belongs in whatever serves static files.

Check your Replit app now

Free, read-only, ten seconds. Then, if you want it watched: weekly re-scans, uptime and error alerts, code checks on the repo.

Scan your app free