API Key Exposure in React Applications
React applications run entirely in the browser, meaning any API key included in the code is visible to users. REACT_APP_ environment variables, hardcoded keys, and direct API calls from components all expose secrets in the JavaScript bundle that attackers can extract in seconds.
Scan Your React AppHow API Key Exposure Manifests in React
API keys leak in React through: Environment variables with REACT_APP_ prefix (Create React App) or VITE_ prefix (Vite) - these are embedded in the build output. Hardcoded API keys in source files that get bundled and shipped to browsers. Direct API calls from React components using secret keys in fetch() or axios headers. Source maps in production builds that make it even easier to find embedded keys.
Real-World Impact
A React dashboard app hardcoded an AWS access key to upload files directly to S3. An attacker extracted the key from the minified JavaScript, used it to access the S3 bucket, downloaded all stored files including user documents and database backups, and then used the same credentials to spin up cryptocurrency mining instances.
Step-by-Step Fix
Create a backend proxy
Route API calls through your backend server which holds the secrets.
// UNSAFE - secret key in React component
const response = await fetch('https://api.openai.com/v1/chat', {
headers: { 'Authorization': `Bearer ${process.env.REACT_APP_OPENAI_KEY}` },
});
// SAFE - call your own backend
const response = await fetch('/api/generate', {
method: 'POST',
body: JSON.stringify({ prompt }),
});
// Backend (Express)
app.post('/api/generate', async (req, res) => {
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: req.body.prompt }],
});
res.json(response.choices[0].message);
});Disable source maps in production
Remove source maps to make it harder to find embedded values.
// For Create React App
// .env.production
GENERATE_SOURCEMAP=false
// For Vite
// vite.config.ts
export default defineConfig({
build: {
sourcemap: false,
},
});Audit for hardcoded secrets
Search your codebase for any hardcoded API keys or tokens.
# Search for common secret patterns
grep -rn "sk-[a-zA-Z0-9]\|api_key.*=.*[\x27\"]\|secret.*=.*[\x27\"]\|password.*=.*[\x27\"]" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
src/Prevention Best Practices
1. Never include secret API keys in React client code, regardless of environment variable naming. 2. Create a backend proxy for all API calls that require secrets. 3. Disable source maps in production builds. 4. Use .gitignore for all .env files. 5. Understand that Firebase/Supabase public keys ARE safe in client code.
How to Test
1. Open browser DevTools > Sources and search for "api_key", "secret", "sk-". 2. Check the Network tab for requests containing API keys in headers or URLs. 3. Grep your source code for hardcoded keys and REACT_APP_/VITE_ secrets. 4. Check if source maps are enabled in production. 5. Use Vibe App Scanner to detect exposed API keys in your React application.
Frequently Asked Questions
Can I safely use any API keys in React?
Only public/restricted API keys designed for client-side use. Firebase API keys, Supabase anon keys, Stripe publishable keys, and Google Maps restricted keys are safe. Secret keys (Stripe secret, OpenAI, AWS credentials) must never be in client code.
Does minification protect my API keys?
No. Minification changes variable names but does not encrypt string values. API keys embedded as strings are visible in minified code. Attackers regularly search minified bundles for key patterns.
How do I use environment variables safely in React?
For public values (analytics IDs, public API keys), REACT_APP_ or VITE_ vars are fine. For secrets, do not use client-side env vars at all. Create a backend API that holds the secrets and have React call your backend instead.
Related Security Resources
Is Your React App Vulnerable to API Key Exposure?
VAS automatically scans for api key exposure vulnerabilities in React applications and provides step-by-step remediation guidance with code examples.
Scans from $5, results in minutes. Get actionable fixes tailored to your React stack.