eToro’s Billion Blunder: Hardcoded API Keys Exposed in Client-Side JavaScript – Here’s How to Find and Fix Them Before Hackers Do + Video

Listen to this Post

Featured Image

Introduction:

Hardcoded API keys and tokens in client-side JavaScript represent one of the most elementary yet devastating security oversights. As demonstrated by a recent Bugcrowd disclosure on eToro, exposing these secrets directly in browser-accessible code allows any attacker to extract them via simple developer tools, potentially leading to unauthorized backend access, data breaches, and complete compromise of application functionality.

Learning Objectives:

  • Identify and extract hardcoded API keys, tokens, and secrets from client-side JavaScript using browser developer tools and automated scanners.
  • Exploit exposed API keys to perform unauthorized actions, escalate privileges, or exfiltrate sensitive data (ethical testing only).
  • Implement secure remediation strategies including environment variables, backend proxying, and secrets management services.

You Should Know:

  1. How to Discover Hardcoded Secrets in Client-Side JavaScript

What this is:

Client-side JavaScript files are downloaded to every user’s browser. Any string literal containing words like “api_key”, “token”, “secret”, “password”, “auth”, or “bearer” can be trivially extracted. Attackers routinely scan for these patterns using browser dev tools or automated crawlers.

Step-by-step guide to manual discovery (ethical testing only):

  1. Open the target website (e.g., `https://www.etoro.com`) in Chrome or Firefox.
  2. Press `F12` to open Developer Tools → Navigate to the Sources tab.
  3. Expand the file tree and locate `.js` or bundled JavaScript files (often named main..js, vendor..js, chunk..js).
  4. Use the search tool (Ctrl+Shift+F inside Sources) and search for keywords:
    – `api_key`
    – `apikey`
    – `token`
    – `secret`
    – `authorization`
    – `Bearer`
    – `”sk-` (Stripe secret keys)
    – `”AKIA` (AWS access keys)
  5. Review each match. If you find a hardcoded string resembling a key, copy it.

Linux command-line extraction (for downloaded JS files):

 Download all JS files from a target domain
wget -r -l 1 -A .js https://example.com

Grep for common secret patterns
grep -E "(api_key|apikey|token|secret|password|AKIA|sk_live)" .js

Using ripgrep for recursive search with context
rg -i "api[_-]?key|token|secret|authorization" -C 2

Windows PowerShell equivalent:

 Download and search JS files
Invoke-WebRequest -Uri "https://example.com/app.js" -OutFile "app.js"
Select-String -Path ".js" -Pattern "api_key|apikey|token|secret" -CaseSensitive

Automated tools for bug bounty hunters:

  • Burp Suite – Use the “JS Miner” extension or the built-in “Find references” on response bodies.
  • SecretFinder – Python tool for extracting secrets from JS:
    git clone https://github.com/m4ll0k/SecretFinder.git
    cd SecretFinder
    pip install -r requirements.txt
    python secretfinder.py -u https://example.com -e -o cli
    
  • LinkFinder – Extracts endpoints and potential secrets:
    python linkfinder.py -i https://example.com/main.js -o cli
    
  1. Exploiting Exposed API Keys – Proof of Concept (Ethical Testing Only)

What this does:

Once you have an API key from client-side JS, you can use it to make authenticated requests to the backend. If the key lacks proper scope restrictions (e.g., no IP whitelisting, no referer validation), an attacker can call any API endpoint that the frontend normally uses.

Step-by-step exploitation guide (test only on assets you own or have permission for):

  1. Extract the key using the manual method above. Example found in JS:
    var config = {
    apiKey: "abc123xyz456",
    token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
    };
    

  2. Identify API endpoints – Search the same JS files for URLs containing /api/, /v1/, /graphql, or relative paths like "/user/profile".

3. Test the key with cURL (Linux/macOS):

 Basic authentication header
curl -X GET "https://api.target.com/v1/user/data" \
-H "X-API-Key: abc123xyz456" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Check for IDOR by incrementing user IDs
curl -X GET "https://api.target.com/v1/user/12345" \
-H "X-API-Key: abc123xyz456"

4. Windows PowerShell equivalent:

$headers = @{
"X-API-Key" = "abc123xyz456"
"Authorization" = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Invoke-RestMethod -Uri "https://api.target.com/v1/user/data" -Headers $headers -Method Get
  1. Test for privilege escalation – If the key belongs to a low-privileged user, try calling admin endpoints like /admin/users, /internal/config, or /debug/vars. Use wordlists to fuzz paths:
    ffuf -u https://api.target.com/FUZZ -w /usr/share/wordlists/dirb/common.txt -H "X-API-Key: abc123xyz456"
    

Real-world impact example (eToro scenario):

If the exposed key allowed trade execution, an attacker could place unauthorized buy/sell orders. If it allowed user data access, PII (names, emails, trading history) could be leaked. If it allowed withdrawal endpoints, funds could be stolen.

3. Mitigation: How to Never Hardcode Secrets Again

What this does:

Secrets must never appear in client-side code. Instead, use a backend proxy that stores keys server-side, implement short-lived tokens, and leverage cloud secrets managers.

Step-by-step secure implementation guide:

  1. Move all API calls that require keys to a backend endpoint.

Instead of:

// BAD - client-side
fetch('https://api.external.com/data', {
headers: { 'X-API-Key': 'hardcoded_key' }
});

Do:

// GOOD - client calls your backend
fetch('/api/proxy/data');

2. On your backend (Node.js example):

// Read from environment variable
const API_KEY = process.env.EXTERNAL_API_KEY;

app.get('/api/proxy/data', async (req, res) => {
const response = await fetch('https://api.external.com/data', {
headers: { 'X-API-Key': API_KEY }
});
res.json(await response.json());
});
  1. Use cloud secrets management – Never store keys in `.env` files committed to git.

– AWS: `aws secretsmanager get-secret-value –secret-id my-api-key`
– Azure: `az keyvault secret show –name my-secret –vault-name myvault`
– GCP: `gcloud secrets versions access latest –secret=”my-secret”`

4. Implement CSP (Content Security Policy) headers to restrict where scripts can send data:

 In Apache .htaccess or Nginx config
Content-Security-Policy: default-src 'self'; script-src 'self' trusted-cdn.com; connect-src 'self' api.yourdomain.com
  1. Automated detection in CI/CD – Scan for secrets before deployment:
    Using truffleHog
    trufflehog filesystem --directory ./frontend --entropy=True
    
    Using gitleaks
    gitleaks detect --source ./frontend --verbose
    
    Using detect-secrets (Python)
    detect-secrets scan --update .secrets.baseline
    

  2. API Key Hardening – Restrict Scope and Rotation

What this does:

Even if a key leaks, proper restrictions limit damage. Implement IP whitelisting, referer validation, and short expiration times.

Step-by-step hardening:

  1. IP whitelisting – In your API gateway (AWS API Gateway, Kong, Nginx):
    Nginx example
    location /api/ {
    allow 203.0.113.0/24;
    deny all;
    proxy_pass http://backend;
    }
    

  2. Referer validation – Check that requests originate from your domain:

    // Express.js middleware
    app.use('/api', (req, res, next) => {
    const referer = req.headers.referer;
    if (!referer || !referer.startsWith('https://yourdomain.com')) {
    return res.status(403).json({ error: 'Invalid source' });
    }
    next();
    });
    

  3. Short-lived tokens with rotation – Use JWT with 15-minute expiry and a refresh token flow. Never use long-lived static keys in mobile/web clients.

  4. Audit and revoke exposed keys immediately – If a key is found in client-side JS:

    Revoke in AWS IAM
    aws iam delete-access-key --access-key-id AKIA...
    
    Rotate immediately and redeploy
    

  5. Setting Up a Bug Bounty Pipeline to Catch Client-Side Secrets

What this does:

Proactively scan your own JavaScript bundles before they reach production, using automated tools in your CI/CD pipeline.

Step-by-step pipeline configuration (GitHub Actions example):

name: Scan JS for Secrets

on:
push:
paths:
- 'frontend//.js'

jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install SecretFinder
run: |
git clone https://github.com/m4ll0k/SecretFinder.git
cd SecretFinder
pip install -r requirements.txt
- name: Run SecretFinder
run: |
python SecretFinder/secretfinder.py -i https://staging.yourdomain.com/main.js -e -o cli | tee secrets.log
- name: Fail if secrets found
run: |
if grep -q "Potential Secret" secrets.log; then
echo "❌ Hardcoded secrets detected in JS!"
exit 1
fi

What Undercode Say:

  • Never trust client-side code – Any secret shipped to the browser is a public secret. Always assume attackers will find it within minutes of deployment.
  • Shift-left security works – Automating secret scanning in CI/CD catches these mistakes before they reach production, saving millions in potential breach costs.

The eToro disclosure (reported via Bugcrowd) is a textbook case of a vulnerability that should never exist in 2025. Yet it persists because developers prioritize speed over security and treat API keys as harmless configuration. The reality: exposed keys are often the first step in a chain leading to full account takeover, data exfiltration, or financial fraud. Organizations must implement three layers of defense: (1) backend proxying to remove keys from frontend entirely, (2) strict API gateway policies (IP whitelist, referer checks, rate limiting), and (3) automated pre-commit and CI/CD scanning tools. For bug bounty hunters, client-side JavaScript remains a goldmine – spend your time grepping for `api_key` and `token` before touching complex SQLi or XSS. The simplest findings often pay the highest bounties because they represent fundamental architectural failures.

Prediction:

As more companies adopt Jamstack and serverless architectures, the trend of bundling API keys into frontend builds will initially increase due to developer inexperience. However, regulatory pressure (GDPR, CCPA, and emerging API security laws) combined with AI-powered static analysis tools will drive a 60% reduction in client-side secret exposures by 2027. Platforms like Bugcrowd and HackerOne will see a spike in these low-hanging-fruit reports, forcing organizations to implement automated secret rotation and real-time key revocation. The long-term solution lies in standards like WebAuthn and passkeys eliminating the need for API keys altogether, but until then, every JavaScript file is a treasure map waiting to be read.

▶️ Related Video (64% Match):

🎯Let’s Practice For Free:

IT/Security Reporter URL:

Reported By: Pankaj Kedia – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeTesting & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky