In our scans of Replit-deployed apps, hardcoded API keys appeared in 58% of flagged projects. That rate is higher than Bolt.new or Netlify deployments, and the cause is consistent: Replit Agent writes API calls with the key value inline instead of referencing process.env. The app works immediately, the leak is invisible unless you look at the source, and if the Repl is public (the default), anyone who visits the Repl URL can click Files and read the key directly.
This guide walks you through finding the leak, rotating the key, and moving secrets to the Replit Secrets tab so they never appear in your source files again.
TL;DR
Replit API key exposure usually comes from Replit Agent hardcoding the key directly in a source file, not from client-bundle issues like VITE_ prefixes. If your Repl is public, anyone can read your source code from the Replit UI. Rotate the key now, move it to the Replit Secrets tab (Tools > Secrets), and replace the inline value with process.env.SECRET_NAME. Check your Repl's visibility setting while you clean up.
Why Replit Exposure Is Different
Unlike Bolt.new or Lovable apps where the problem is usually a VITE_-prefixed variable baked into a browser JavaScript bundle, Replit apps are typically server-side Node.js, Python, or Express apps. The exposure is simpler: the key is written into a .js or .py file, and that file is readable by anyone who can view your Repl.
Two things make this especially risky:
Public Repls expose source code. A new Repl is public by default. Anyone who finds or guesses your Repl URL can click the Files panel and read every source file. There is no build process to obscure the value.
Replit Agent writes working code immediately. When Agent adds an OpenAI integration, it sometimes echoes the key value from your conversation context into the code directly. The result runs on the first try, so there is no obvious error prompting a review.
Step 1: Find the Exposed Key
Search your source files for hardcoded key values. Open the Replit shell (bottom panel, Shell tab) and run:
# Search for common key prefixes hardcoded in source files
grep -rn "sk-proj-\|sk-ant-\|sk_live_\|rk_live_\|AKIA\|eyJhbGci" . \
--include="*.js" --include="*.ts" --include="*.py" --include="*.jsx" --include="*.tsx" \
--exclude-dir=node_modules --exclude-dir=.git
# Also search for generic inline key assignments
grep -rn "apiKey.*=.*['\"][A-Za-z0-9_\-]\{20,\}" . \
--include="*.js" --include="*.ts" --include="*.py" \
--exclude-dir=node_modules
If a match shows an actual key value (not a process.env. reference), that key is hardcoded.
Check your .env file for committed secrets. If your Repl is connected to a GitHub repository:
# Check if .env was ever committed
git log --all --full-history -- .env
git log --all --full-history -- .env.local
If these commands return commits, the secrets in those files are in your git history.
Check your Repl's visibility. In the Replit UI, click the Repl name at the top, then Settings. Look for the Privacy setting. If it is set to Public, your source code is readable by anyone. Even if you fix the code now, anyone who viewed it while it was public may have copied the key.
CheckYourVibe scans your deployed Replit app's HTTP responses and JavaScript assets for API keys visible from outside the server. It catches keys printed to client-visible responses, exposed in error messages, or returned in API payloads.
Step 2: Rotate the Exposed Key Immediately
Do not fix the code first. The key is already out. Rotate it now.
Generate a new key in the affected service's dashboard. Most services let you keep multiple active keys, so production stays live during the switchover.
Add the new key to Replit Secrets. In your Repl, click Tools in the left sidebar, then Secrets. Click "Add new secret." Enter the variable name (like OPENAI_API_KEY) and paste the new key value. Replit encrypts it and injects it as an environment variable when your app runs.
Restart your Repl to pick up the new secret value. Click Stop and then Run, or use the shell: kill 1 triggers a clean restart.
Revoke the old key in the service dashboard. Do not skip this step. Any key visible in source code should be treated as compromised, even if you cannot confirm it was accessed.
Check usage logs. Review the affected service's dashboard for unexpected usage spikes during the exposure window. OpenAI shows per-key usage; Stripe shows charge history; Supabase shows database query logs.
If your Repl was public and contained a hardcoded key for any meaningful time, treat it as compromised. Rotate it regardless of whether you see abuse. Automated scanners index public Repls; the key may have been copied within minutes of the Repl going live.
Step 3: Remove the Key from Source Files
Now update your code to use the Replit Secret instead of the hardcoded value.
Node.js
Wrong (key hardcoded by Replit Agent):
// main.js - Replit Agent wrote this inline
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: 'sk-proj-abc123...', // visible in source, must be removed
});
Right (reads from Replit Secrets at runtime):
// main.js - reads from Secrets tab, never in source
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY, // set this in Tools > Secrets
});
Python
Wrong:
# main.py - hardcoded by Agent
import openai
client = openai.OpenAI(api_key="sk-proj-abc123...")
Right:
# main.py - reads from Replit Secrets
import os
import openai
client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
How to Set Secrets in Replit
- Click Tools in the left sidebar (or the lock icon).
- Click Secrets.
- Click + New Secret.
- Enter the variable name:
OPENAI_API_KEY. - Paste the key value.
- Click Add Secret.
The secret is now available as process.env.OPENAI_API_KEY (Node.js) or os.environ.get('OPENAI_API_KEY') (Python) every time your Repl runs.
Replit Secrets are not available during the build phase of some deployment types. If your app fails to start with "undefined" for a variable you added to Secrets, check that you are reading it at runtime (when the function is called) rather than at module load time before the secrets are injected.
Step 4: Remove from Git History (if connected to GitHub)
If your Repl is connected to a GitHub repository and the key was committed there, clean the history.
# Install git-filter-repo
pip install git-filter-repo
# Remove .env from all history
git filter-repo --path .env --invert-paths
git filter-repo --path .env.local --invert-paths
After scrubbing, force-push to all remotes. If the GitHub repo was public at any point, treat the key as compromised.
Also add .env to .gitignore:
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
git add .gitignore && git commit -m "chore: gitignore .env files"
Step 5: Check Repl Visibility
After cleaning the code, decide on the right visibility setting for your Repl.
- Private: Only you (and collaborators you invite) can view the source. Choose this for production apps.
- Public: Anyone can view your source code by visiting the Repl URL. Fine for demos or open-source projects, but never with hardcoded secrets.
To change visibility: click your Repl name at the top > Settings > Privacy > set to Private.
Note: Changing to Private now does not undo exposure that happened while it was Public. If the Repl was public with a hardcoded key, rotate the key regardless.
Step 6: Prevent Future Leaks from Replit Agent
Replit Agent generates functional code, but it sometimes writes secrets inline. You can reduce this with explicit prompting.
Add an instruction at the start of your Agent conversation:
"For any API keys or secrets this app needs, store them in Replit Secrets (process.env.SECRET_NAME in Node.js, os.environ.get('SECRET_NAME') in Python). Never hardcode key values in source files."
After Agent generates any code involving an external API, run this check before saving:
grep -rn "sk-proj-\|sk-ant-\|sk_live_\|AKIA" . \
--include="*.js" --include="*.ts" --include="*.py" \
--exclude-dir=node_modules
If this returns any matches with actual key values, replace them with process.env references before the code goes live.
What Goes Where
| Secret type | Where it lives | Accessed via |
|---|---|---|
| OpenAI / Anthropic key | Replit Secrets | process.env.OPENAI_API_KEY or os.environ.get('OPENAI_API_KEY') |
| Stripe secret key | Replit Secrets | process.env.STRIPE_SECRET_KEY |
| Supabase service_role | Replit Secrets | process.env.SUPABASE_SERVICE_ROLE_KEY (server only) |
| Supabase anon key | Replit Secrets (or inline for client) | process.env.SUPABASE_ANON_KEY |
| Database URL | Replit Secrets | process.env.DATABASE_URL |
The Supabase anon key is designed to be public and safe to use in browser code (protected by RLS). Everything else belongs in Secrets.
How do I know if my Replit API key is exposed?
Check two things: (1) Search your source files from the Replit shell with grep -rn "sk-proj-" . --include="*.js" --include="*.py". If it returns an actual key value instead of a process.env reference, the key is hardcoded. (2) Check if your Repl is public (Settings > Privacy). If it is, anyone visiting your Repl URL can read your source code directly from the Files panel.
What is the Replit Secrets tab and how do I use it?
The Secrets tab is Replit's encrypted secrets manager. Open your Repl, click Tools in the left sidebar, then Secrets. Add a key like OPENAI_API_KEY and its value. In Node.js, read it as process.env.OPENAI_API_KEY. In Python, use os.environ.get('OPENAI_API_KEY'). Secrets are encrypted at rest, not visible in source code, and not transferred when someone forks your Repl.
Why does Replit Agent hardcode API keys instead of using Secrets?
Replit Agent generates code that runs immediately. When you ask it to add an API feature, it sometimes writes the key value inline so the code works on the first try. The result is functional but insecure. After Agent generates any code involving an external API, grep for key patterns before saving or running the Repl with the key active.
If my Repl is private, is my hardcoded key safe?
Safer, but not safe. A private Repl hides source from the public, but the key still appears in server logs, error stack traces, and any debug output. If your Repl connects to a GitHub repo, the key may also be in that repo's history. Move it to Replit Secrets regardless of visibility.
Do Replit Secrets transfer when someone forks my Repl?
No. Replit Secrets are tied to your Repl and do not copy when someone forks it. Hardcoded values in source files do transfer with the fork. Always use Secrets rather than inline values so forks cannot inherit your credentials.
Check your Replit deployment for hardcoded API keys, exposed secrets, and security header gaps. Free scan, no signup required.