How Hackers Find Secrets in JavaScript Files (Real Methods)
Every JavaScript file your website serves is fully readable by anyone with a browser. Attackers know this, and they have built an entire methodology around extracting API keys, tokens, internal URLs, and credentials from client-side code. This guide covers exactly how they do it and what you can do to stop it.
Why JavaScript Files Are a Goldmine for Attackers
JavaScript is unique among programming languages in that your source code is delivered directly to the client. Unlike server-side code that runs behind a firewall, every line of JavaScript you ship is visible to anyone who visits your website. Minification and bundling do not change this. They make the code harder to read, but they do not hide it.
Modern web applications often ship megabytes of JavaScript. Within those bundles, developers frequently embed configuration objects, API endpoints, authentication tokens, and service credentials. Sometimes this happens intentionally ("it is just a publishable key"). Other times it happens by accident when a build process pulls in environment variables or when a developer hardcodes a value during debugging and forgets to remove it.
The scale of this problem is enormous. A 2024 study by researchers at Northeastern University found that over 4,000 of the top 100,000 websites exposed at least one active API key or secret in their client-side JavaScript. These were not test keys or publishable tokens. They were live credentials that could be used to access databases, send emails, process payments, or query cloud services without authorization.
Attackers have automated the process of finding these secrets. What used to require manual inspection now happens at scale, with crawlers that download, parse, and scan JavaScript files across millions of domains every day.
Real Methods Hackers Use to Extract Secrets
Method 1: View Source and DevTools
The simplest approach requires nothing more than a browser. Right-click any webpage, select "View Page Source," and you can see every inline script. Open DevTools (F12), navigate to the Sources tab, and you have access to every JavaScript file the page loaded, including those from external CDNs and third-party scripts.
Chrome DevTools even provides a "Search across all files" feature (Ctrl+Shift+F) that lets attackers search every loaded script for patterns like apiKey, secret, token, password, or firebase. This takes seconds and catches a surprising number of exposed credentials.
# Common search terms attackers use in DevTools
apiKey
api_key
apiSecret
secret
token
password
firebase
aws_access_key
AKIA
sk_live_
pk_live_
Authorization: Bearer
.execute-api.
graphql
Method 2: JavaScript Beautifiers and Deobfuscators
Most production JavaScript is minified, meaning variable names are shortened and whitespace is removed. This makes the code harder to read but does not protect secrets. Attackers use JavaScript beautifiers to reverse this process:
- Prettier / js-beautify reformats minified code into readable form in seconds
- de4js handles common obfuscation techniques including string array rotation and control flow flattening
- synchrony deobfuscates JavaScript protected by obfuscator.io
- webcrack unpacks webpack bundles back into individual modules
Even JavaScript that has been run through an obfuscator like javascript-obfuscator is not safe. The strings (including API keys) must eventually be decoded at runtime, which means they are recoverable. Obfuscation raises the bar slightly, but a motivated attacker with the right tools can reverse most obfuscation in minutes.
Method 3: Regex Pattern Scanning
Attackers write regular expressions that match known secret formats. Each cloud provider and service has a distinct key pattern, making automated detection straightforward:
# AWS Access Key IDs
AKIA[0-9A-Z]{16}
# AWS Secret Keys (high entropy base64)
[A-Za-z0-9/+=]{40}
# Stripe Live Secret Key
sk_live_[0-9a-zA-Z]{24,}
# Stripe Publishable Key
pk_live_[0-9a-zA-Z]{24,}
# Google API Key
AIza[0-9A-Za-z\-_]{35}
# Firebase Config
apiKey.*?AIza[0-9A-Za-z\-_]{35}
# GitHub Personal Access Token
ghp_[0-9a-zA-Z]{36}
# Slack Webhook
hooks\.slack\.com/services/T[A-Z0-9]{8}/B[A-Z0-9]{8}/[a-zA-Z0-9]{24}
# Generic JWT
eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*
# Private Key
-----BEGIN (RSA |EC )?PRIVATE KEY-----
These patterns can be run against downloaded JavaScript files using simple command-line tools. An attacker can scan an entire website's JavaScript in under a minute.
Method 4: Automated Crawlers and Recon Tools
The security research community has built specialized tools for extracting secrets from JavaScript files. Attackers use these same tools:
LinkFinder is a Python tool that parses JavaScript files to find API endpoints and URL paths. It uses jsbeautifier to deobfuscate code and then applies regex patterns to extract anything that looks like a URL, path, or API route. This reveals hidden admin panels, internal APIs, and undocumented endpoints.
# LinkFinder - extract endpoints from JS files
python3 linkfinder.py -i https://target.com/app.js -o cli
# Extract from all JS files on a domain
python3 linkfinder.py -i https://target.com -d -o results.html
SecretFinder extends LinkFinder's approach to focus specifically on secrets. It scans JavaScript for API keys, tokens, credentials, and other sensitive data using a comprehensive set of regex patterns:
# SecretFinder - extract secrets from JS files
python3 SecretFinder.py -i https://target.com/main.js -o cli
# Scan with extended regex set
python3 SecretFinder.py -i https://target.com -e -o results.html
Nuclei from ProjectDiscovery includes JavaScript analysis templates that detect exposed secrets, API endpoints, and misconfigurations. It scales to thousands of targets and integrates with CI/CD pipelines.
JSFScan combines multiple tools (LinkFinder, SecretFinder, getjswords, and more) into a single automated pipeline. Point it at a domain and it downloads all JavaScript files, extracts endpoints, scans for secrets, and generates a comprehensive report.
Wayback Machine crawling is another technique attackers use. Historical JavaScript files archived by the Wayback Machine may contain secrets that have since been removed from the live site. Tools like waybackurls and gau (GetAllURLs) retrieve archived JavaScript URLs, and attackers scan those old files for credentials that may still be valid.
# Get historical JS files from Wayback Machine
echo "target.com" | waybackurls | grep "\.js$" | sort -u > js_files.txt
# Download and scan each file
while read url; do
curl -s "$url" | grep -E "(api_key|apiKey|secret|token|password)" >> findings.txt
done < js_files.txt
Method 5: Source Map Exploitation
Source maps are files that map minified JavaScript back to the original source code. They are intended for debugging, but when left accessible in production, they expose your entire unminified codebase. An attacker who finds a source map can read your code exactly as you wrote it, complete with comments, variable names, and configuration.
Source maps are typically referenced in a comment at the end of a JavaScript file:
//# sourceMappingURL=app.js.map
Attackers check for these references and attempt to download the corresponding .map file. Tools like unwebpack-sourcemap can reconstruct the entire original project directory structure from a single source map file.
Scan Your Domain for Exposed Secrets and JavaScript Files
SecureBin Exposure Checker scans your domain for exposed configuration files, source maps, API endpoints, and other sensitive data. 19 parallel checks, instant results.
Scan Your Domain FreeCommon Secrets Found in JavaScript Files
Based on public research and bug bounty reports, these are the most frequently exposed secrets in client-side JavaScript:
API Keys and Service Credentials
- Google Maps / Places API keys are the single most common secret in client-side JS. While Google considers these "publishable," unrestricted keys can rack up thousands of dollars in charges on Geocoding, Directions, and Places APIs.
- Firebase configuration objects contain the API key, auth domain, project ID, and storage bucket. With an unrestricted Firebase key, attackers can read and write to your Firestore database and access Firebase Storage.
- AWS access keys (starting with
AKIA) are sometimes hardcoded by developers who intended to use them only temporarily. These provide direct access to AWS services. Learn more in our guide on checking if your API key is exposed. - Stripe publishable keys (
pk_live_) are designed to be public, but Stripe secret keys (sk_live_) occasionally end up in JavaScript bundles through environment variable misconfiguration. - Algolia, Typesense, and other search service keys are often embedded in frontend code with overly broad permissions.
Internal URLs and Hidden Endpoints
- GraphQL endpoints are often discoverable in JavaScript and may expose an introspection query that reveals your entire data schema.
- Admin panel URLs like
/admin,/dashboard,/internal-apiare frequently hardcoded in JavaScript route definitions. - Staging and development server URLs in JavaScript configuration objects point attackers to less-secured environments.
- API gateway endpoints (e.g.,
.execute-api.amazonaws.com) reveal your backend infrastructure. - WebSocket URLs for real-time features may accept unauthenticated connections.
Authentication Tokens and Session Data
- Hardcoded JWTs used as default or fallback authentication tokens
- OAuth client secrets that should only exist on the server
- Service account credentials for backend services
- Bearer tokens stored in JavaScript variables instead of HTTP-only cookies
Real-World Examples of JavaScript Secret Leaks
The Uber Internal Dashboard Exposure
In a widely reported incident, a security researcher discovered that Uber's JavaScript files contained internal API endpoints and authentication tokens that provided access to internal dashboards. The JavaScript bundles contained hardcoded API base URLs and authorization headers that were meant for internal tooling but were shipped to production clients. This is a textbook example of build-time configuration leaking into production bundles.
Firebase Database Takeovers
Researchers from Appthority found that 113 GB of data from 2,271 Firebase databases was accessible due to misconfigured security rules combined with Firebase configuration objects exposed in JavaScript. The Firebase API keys in JavaScript were not the vulnerability by themselves. The vulnerability was that those keys pointed to databases with no security rules, allowing anyone to read and write data. The JavaScript exposure made the databases trivially discoverable.
Exposed Stripe Keys in E-Commerce
Bug bounty hunters regularly report Stripe secret keys found in JavaScript bundles of e-commerce sites. In one case documented on HackerOne, a major retailer had their Stripe sk_live_ key embedded in a webpack bundle due to a misconfigured .env file being included in the build. The key had full access to customer payment data, refund capabilities, and account settings. For more on protecting API keys, see our guide on securing API keys in code.
AWS Keys in Single-Page Applications
A recurring pattern involves React and Vue applications that use AWS Amplify or direct SDK calls with hardcoded credentials. Developers embed AWS access keys in frontend code to allow direct S3 uploads or DynamoDB queries. Attackers extract these keys and use them to enumerate S3 buckets, access DynamoDB tables, or pivot to other AWS services depending on the IAM permissions attached to the credentials.
How to Detect Secrets in Your Own JavaScript
Manual Inspection
Start by checking what your site actually serves to browsers. Open your site in Chrome, press F12, go to the Sources panel, and search (Ctrl+Shift+F) for each of these terms:
apiKey
api_key
secret
token
password
firebase
AKIA
sk_live
pk_live
Authorization
Bearer
.execute-api.
graphql
mongodb
postgres
mysql
redis
Also check the Network tab for any JavaScript files loaded from external domains. Third-party scripts can contain your configuration if they are dynamically generated.
Automated Scanning with CLI Tools
For a systematic approach, download all your JavaScript files and scan them with purpose-built tools:
# Download all JS files from your site
wget -r -l 2 -A "*.js" https://your-site.com -P js_dump/
# Scan with TruffleHog
trufflehog filesystem --directory=js_dump/
# Scan with Gitleaks (works on any directory, not just git repos)
gitleaks detect --source=js_dump/ --no-git --verbose
# Quick grep for common patterns
grep -rE "(AKIA[0-9A-Z]{16}|sk_live_|AIza[0-9A-Za-z_-]{35})" js_dump/
Scan Your Domain with SecureBin
The SecureBin Exposure Checker runs 19 parallel security checks against your domain, including checks for exposed configuration files, source maps, and common paths that reveal secrets. It takes seconds and requires no installation or signup. This is the fastest way to get a baseline assessment of your client-side exposure.
Prevention: Stop Secrets from Reaching JavaScript
Never Embed Secrets in Frontend Code
The fundamental rule is simple: never put anything in client-side JavaScript that you would not be comfortable printing on a billboard. This includes API keys, database credentials, service tokens, and internal URLs. If a value needs to remain confidential, it must stay on the server.
Use Environment Variables Correctly
Environment variables are often misunderstood. In frameworks like React (Create React App) and Next.js, environment variables prefixed with REACT_APP_ or NEXT_PUBLIC_ are embedded directly into the JavaScript bundle at build time. This means they are visible to anyone who views your JavaScript.
# WRONG: This ends up in the client bundle
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_abc123
# RIGHT: This stays server-side only
STRIPE_SECRET_KEY=sk_live_abc123
Only use the public/client prefix for values that are genuinely safe to expose, like publishable Stripe keys, public analytics IDs, or your site URL. For more on this topic, read our guide on exposed .env files.
Build Backend Proxies for Sensitive API Calls
Instead of calling third-party APIs directly from the browser with your API key, route requests through your own backend:
// WRONG: API key exposed in browser
fetch('https://api.service.com/data?key=SECRET_KEY')
// RIGHT: Call your own backend, which adds the key server-side
fetch('/api/proxy/service-data')
Your backend proxy adds the API key from server-side environment variables before forwarding the request. The client never sees the key. This also gives you a place to add rate limiting, caching, and request validation.
Implement Token Rotation
For keys that must be partially exposed (like Firebase configuration), implement aggressive rotation and restriction:
- Restrict API keys to specific domains (HTTP referrer restrictions)
- Restrict keys to specific APIs (do not use unrestricted keys)
- Set up billing alerts to catch unauthorized usage immediately
- Rotate keys on a regular schedule, at minimum quarterly
Content Security Policy (CSP)
A strict Content Security Policy limits which scripts can execute on your page and where they can connect. While CSP does not hide secrets from JavaScript, it limits what an attacker can do if they find a way to inject code into your page:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.your-domain.com;
connect-src 'self' https://api.your-domain.com;
style-src 'self' 'unsafe-inline';
Remove Source Maps from Production
Configure your build tool to exclude source maps from production builds:
# webpack.config.js (production)
module.exports = {
devtool: false, // No source maps in production
};
# next.config.js
module.exports = {
productionBrowserSourceMaps: false,
};
If you need source maps for error tracking (e.g., Sentry), upload them directly to your error tracking service and do not serve them publicly.
Common Mistakes That Lead to Secret Exposure
- Using NEXT_PUBLIC_ or REACT_APP_ for secret values. These prefixes explicitly mark variables for client-side inclusion. Developers who do not understand this mechanism frequently expose database URLs, API secrets, and admin credentials.
- Committing .env files to the repository. If your .env file is in your git repo and your build process uses it, secrets end up in the build output. Always add
.env*to.gitignore. - Hardcoding secrets during development and forgetting to remove them. A "temporary" API key in a config file becomes a permanent leak once it reaches production.
- Assuming minification protects secrets. Minification changes variable names and removes whitespace. It does not encrypt or hide string values. API keys are strings, and they survive minification completely intact.
- Trusting obfuscation as a security measure. JavaScript obfuscation makes code harder to read, but strings must be decoded at runtime. Any value the JavaScript engine can access, an attacker can access too.
- Leaving debug or development builds in production. Unminified builds, verbose logging, and debug endpoints all increase the attack surface.
- Not checking third-party scripts. Analytics tags, chat widgets, A/B testing tools, and other third-party scripts may contain your configuration or inject their own keys into the page.
Best Practices Checklist
- Audit your JavaScript bundles before every release. Search for known secret patterns using regex. Make this part of your CI/CD pipeline.
- Use a secret scanner in CI. Tools like Gitleaks, TruffleHog, or detect-secrets should run on every pull request. Block merges that contain secrets.
- Separate public and private configuration. Create distinct configuration files or environment variable sets for values that are safe to expose versus values that must remain server-side.
- Implement backend proxies for all sensitive API calls. No API key that provides write access or accesses private data should ever appear in client-side code.
- Restrict every API key to the minimum necessary permissions. Google keys should be restricted to specific APIs and referrers. AWS credentials should use IAM policies with least privilege. Stripe keys should be scoped to the minimum required operations.
- Remove source maps from production. Upload them to your error tracking service instead of serving them publicly.
- Monitor for leaked credentials. Use GitHub secret scanning, Google's API key alerts, and AWS CloudTrail to detect unauthorized usage. Run periodic scans of your production JavaScript with the tools described in this article.
- Rotate keys immediately when exposure is suspected. Do not wait to confirm the leak. Rotate first, investigate second.
- Use HTTP-only cookies for authentication tokens. Never store JWTs or session tokens in JavaScript-accessible storage (localStorage, sessionStorage, or global variables).
- Review your webpack/Vite/build configuration. Understand exactly which environment variables are included in the client bundle and verify that no secret values leak through the build process.
Frequently Asked Questions
Are Google Maps API keys safe to put in JavaScript?
Google Maps API keys are designed to be used client-side, but they are only safe if properly restricted. You must configure HTTP referrer restrictions in the Google Cloud Console so the key only works on your domain. You should also restrict the key to only the specific APIs you use (Maps JavaScript API, Places API, etc.). Without these restrictions, anyone who copies your key can use it on their own site and run up charges on your account. Even with restrictions, monitor your usage dashboard for anomalies.
Can minification or obfuscation protect my secrets?
No. Minification shortens variable names and removes whitespace, but string literals (which is what API keys are) remain completely unchanged. Obfuscation adds layers of encoding and control flow manipulation, but the strings must be decoded at runtime for the application to function. Tools like de4js and synchrony can reverse most obfuscation in minutes. If a value appears anywhere in your JavaScript, assume it is public.
How do I find all the JavaScript files my site loads?
Open Chrome DevTools (F12), go to the Network tab, reload the page, and filter by "JS" in the type column. This shows every JavaScript file the page loads, including third-party scripts, dynamically loaded modules, and service workers. You can also use command-line tools like wget with recursive mode to download all referenced JavaScript files, or use the SecureBin Exposure Checker to scan your domain for exposed files automatically.
What should I do if I find a secret in my production JavaScript right now?
Rotate the key immediately. Go to the provider's dashboard and generate a new key. Update your server-side configuration with the new key. Then fix the root cause: move the secret out of client-side code and into server-side environment variables or a secrets manager. Deploy a new build that does not contain the old key. Finally, check the provider's access logs for any unauthorized usage during the exposure window. Do not assume the key was not discovered just because you found it quickly. Automated scanners are fast.
Run a Free Exposure Scan with SecureBin.ai
Check your domain for exposed secrets, configuration files, source maps, and 80+ sensitive paths. 19 parallel security checks, instant results, no signup required.
Check Your Domain FreeThe Bottom Line
JavaScript files are the most overlooked attack surface on the web. Every script your site serves is fully readable, and attackers have built sophisticated tooling to extract secrets from them at scale. The defense is straightforward: keep secrets on the server, proxy sensitive API calls through your backend, scan your bundles for leaked credentials, and restrict every key to the minimum required permissions.
Start by running a scan with the SecureBin Exposure Checker to see what your site is exposing right now. Then implement the prevention checklist above to close the gaps.
Related reading: How to Check if API Key is Exposed, Exposed .env Files: The #1 Secret Leak, How to Secure API Keys in Code, How Hackers Find Exposed API Keys.