Back to Blog
critical SEVERITY5 min read

How hardcoded API key exposure happens in JavaScript and how to fix it

A critical security vulnerability was discovered in `js/douban.js` where the Douban API key (`0ac44ae016490db2204ce0a042db2916`) was hardcoded directly in client-side JavaScript. This exposed the API credential to any user who could view the page source or use browser developer tools. The fix removed the hardcoded key, preventing unauthorized API access and potential abuse.

O
By Orbis AppSec
Published July 28, 2026Reviewed July 28, 2026

Answer Summary

This vulnerability is a hardcoded API key exposure (CWE-798) in JavaScript where the Douban miniapp API key was embedded directly in client-side code at `js/douban.js:697`. Any user could extract this key using browser developer tools. The fix removes the hardcoded value by setting `miniapp_apikey=""`, requiring the key to be provided through a secure server-side mechanism instead.

Vulnerability at a Glance

cweCWE-798
fixRemove hardcoded key and implement server-side credential management
riskUnauthorized API access, quota abuse, service impersonation
languageJavaScript
root causeAPI key embedded directly in client-side JavaScript code
vulnerabilityHardcoded API Key Exposure

Introduction

In the js/douban.js file, we discovered a critical hardcoded API key exposure at line 697. The Douban miniapp API key (miniapp_apikey="0ac44ae016490db2204ce0a042db2916") was embedded directly in a JavaScript string that gets delivered to every user's browser. This file handles integration with the Douban API service for fetching movie and TV show data, but the credential management approach created a severe security risk.

The problematic code was part of a minified JavaScript block within the 推荐 property of a rule object:

let miniapp_apikey="0ac44ae016490db2204ce0a042db2916";

This matters because any developer working with third-party API integrations needs to understand: client-side code is never a safe place for credentials.

The Vulnerability Explained

When JavaScript runs in a browser, the source code is completely accessible to users. Anyone can:

  1. Right-click and "View Page Source"
  2. Open browser Developer Tools (F12) and inspect the Sources tab
  3. Use the Network tab to see API requests with the key attached

In this specific case, the miniapp_request function in douban.js used the hardcoded key for every API call:

function miniapp_request(path, query) {
    try {
        let url = douban_api_host + path;
        query.apikey = miniapp_apikey;  // Hardcoded key attached to every request
        fetch_params.headers = oheaders;
        url = buildUrl(url, query);
        let html = fetch(url, fetch_params);
        return JSON.parse(html);
    } catch(e) {
        print("发生了错误:" + e.message);
        return {};
    }
}

Attack Scenario

An attacker targeting this application could:

  1. Extract the key: Open js/douban.js in browser DevTools, search for "apikey", and copy 0ac44ae016490db2204ce0a042db2916
  2. Abuse the API quota: Make unlimited requests to Douban's API using the stolen key, potentially exhausting rate limits for legitimate users
  3. Impersonate the application: Use the key to access Douban API endpoints, potentially accessing data or functionality meant only for this application
  4. Cause financial damage: If the API key is tied to a paid tier, the attacker could rack up charges against the application owner

Real-World Impact

For this Douban integration specifically:
- The subject_real_time_hotest function fetches trending movies and TV shows
- An attacker could scrape Douban's entire catalog using the exposed key
- The legitimate application could be rate-limited or banned due to abuse
- If Douban tracks API usage, the application owner could face account suspension

The Fix

The fix was straightforward but essential—remove the hardcoded API key entirely:

Before (Vulnerable)

let miniapp_apikey="0ac44ae016490db2204ce0a042db2916";

After (Fixed)

let miniapp_apikey="";

This change in js/douban.js at line 697 ensures that:

  1. No credential is exposed in client-side code
  2. The API integration breaks intentionally until a proper server-side solution is implemented
  3. The attack surface is eliminated immediately

The fix deliberately leaves the variable empty rather than removing the code entirely. This preserves the application structure while forcing developers to implement proper credential management through a secure backend proxy or environment variable injection at build time.

Why This Approach Works

By setting miniapp_apikey="", the code still runs without syntax errors, but API calls will fail authentication. This is the correct behavior because:

  • It prevents the immediate security risk
  • It makes the broken functionality obvious during testing
  • It forces the implementation of a proper secure solution

Prevention & Best Practices

1. Never Embed Secrets in Client-Side Code

This is the golden rule. Anything in JavaScript, HTML, or CSS that reaches the browser is public.

2. Use a Backend Proxy

Instead of calling external APIs directly from the browser:

// ❌ Bad: Direct API call with exposed key
fetch('https://api.douban.com/v2/movie?apikey=SECRET_KEY');

// ✅ Good: Call your own backend, which holds the key securely
fetch('/api/proxy/douban/movie');

Your backend then makes the actual API call with credentials stored in environment variables.

3. Environment Variables at Build Time

For static sites, inject API keys during the build process, but only for keys that are safe to expose (like public analytics IDs):

// Only for truly public keys (e.g., Google Maps public API key)
const publicKey = process.env.REACT_APP_PUBLIC_KEY;

4. Use Secret Scanning Tools

Implement pre-commit hooks and CI/CD checks that scan for credential patterns:

  • git-secrets: Prevents committing secrets
  • truffleHog: Scans git history for high-entropy strings
  • Semgrep: Static analysis with secret detection rules

5. Rotate Compromised Keys Immediately

If a key has been exposed (like this Douban key), assume it's compromised:

  1. Generate a new API key in the service's dashboard
  2. Update your secure backend configuration
  3. Revoke the old key
  4. Monitor for unauthorized usage

Key Takeaways

  • The miniapp_apikey in douban.js was visible to every user who loaded the page, making extraction trivial
  • Client-side JavaScript is never secure for credentials—treat all browser code as public
  • The miniapp_request function attached the exposed key to every Douban API call, amplifying the risk
  • Removing the hardcoded value forces proper architecture—a backend proxy should handle API authentication
  • This exact pattern (apikey="..." in JS) is easily detectable with static analysis, making prevention straightforward

How Orbis AppSec Detected This

  • Source: The hardcoded string "0ac44ae016490db2204ce0a042db2916" assigned to miniapp_apikey in js/douban.js:697
  • Sink: The query.apikey = miniapp_apikey assignment in the miniapp_request function, which attached the credential to outgoing API requests
  • Missing control: No server-side proxy or secure credential injection mechanism; the API key was embedded directly in deliverable client-side code
  • CWE: CWE-798 (Use of Hard-coded Credentials)
  • Fix: Removed the hardcoded API key value, setting miniapp_apikey="" to eliminate client-side credential exposure

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.

Conclusion

Hardcoded API keys in client-side JavaScript represent one of the most common and easily exploitable security vulnerabilities. The Douban API key exposure in js/douban.js demonstrates how a single line of code—miniapp_apikey="0ac44ae016490db2204ce0a042db2916"—can compromise an entire API integration.

The fix is simple: never put secrets in client-side code. Use backend proxies, environment variables on the server, and automated scanning tools to catch these issues before they reach production. Remember, if code runs in a browser, users can read it.

References

Frequently Asked Questions

What is hardcoded API key exposure?

Hardcoded API key exposure occurs when authentication credentials are embedded directly in source code, making them accessible to anyone who can view the code, especially in client-side applications.

How do you prevent hardcoded API key exposure in JavaScript?

Never embed API keys in client-side code. Use environment variables, server-side proxies, or secure backend services to handle API authentication without exposing credentials to browsers.

What CWE is hardcoded API key exposure?

CWE-798: Use of Hard-coded Credentials covers this vulnerability, which describes the risk of embedding authentication data directly in source code.

Is obfuscating JavaScript enough to prevent API key exposure?

No, obfuscation only makes extraction harder, not impossible. Determined attackers can still reverse-engineer obfuscated code or intercept network requests to obtain credentials.

Can static analysis detect hardcoded API keys?

Yes, static analysis tools can detect patterns like hardcoded strings assigned to variables named "apikey", "secret", or "token", making this vulnerability highly detectable during code review.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1

Related Articles

critical

How Denial of Service via gzip bomb happens in Node.js tar and how to fix it

A critical Denial of Service vulnerability (CVE-2026-59873) was discovered in the node-tar package where attackers could craft malicious gzip archives that expand to consume all available system resources. This vulnerability affected version 7.5.15 of the tar package and was fixed by upgrading to version 7.5.19. The fix protects applications from resource exhaustion attacks when processing untrusted archive files.

critical

How unsafe eval() code execution happens in JavaScript game scripting and how to fix it

A critical arbitrary code execution vulnerability was discovered in `scripts/CommandBlock.js` where user-provided input from a text dialog was directly concatenated into an `eval()` call without any sanitization or sandboxing. The fix replaces the dangerous `eval()` with a `new Function()` constructor, which provides better scope isolation and eliminates the string concatenation injection vector.

high

How HTTP Transport Hijacking via Prototype Pollution happens in Node.js axios and how to fix it

CVE-2026-42033 is a high-severity prototype pollution vulnerability in axios versions prior to 1.15.1 that could allow attackers to hijack HTTP transport configuration through malicious input. This vulnerability affects any Node.js application using vulnerable axios versions to make HTTP requests. The fix involves upgrading axios to version 1.15.1, which patches the prototype pollution flaw and prevents transport layer attacks.

critical

How buffer overflow in Intel SGX enclave ECALLs happens in C and how to fix it

A critical buffer overflow vulnerability was discovered in Intel SGX enclave functions `ecall_encrypt_data` and `ecall_decrypt_data` in `backend/sgx/enclave/enclave.c`. The functions performed memory operations without validating that the provided buffer lengths matched the actual allocated buffer sizes, allowing an attacker controlling the untrusted application to trigger heap corruption within the secure enclave by passing oversized length parameters.

critical

How Server-Side Request Forgery happens in Node.js server.js and how to fix it

A Server-Side Request Forgery (SSRF) vulnerability was discovered in `server.js` and `worker.js`, where user-supplied `config` URL parameters were passed directly to `fetchWithAuth()` without any validation. This allowed attackers to force the application to make requests to internal network addresses, cloud metadata endpoints like `169.254.169.254`, or `file://` URIs. The fix introduces an `isAllowedUrl()` allowlist function that rejects private IP ranges, loopback addresses, and non-HTTP(S) pr

critical

How command injection via execSync() happens in Node.js CLI tools and how to fix it

A critical command injection vulnerability was discovered in `packages/core/bin/cli.js` where the `copyToClipboard` function used `execSync()` with shell command strings. Combined with insufficient filename sanitization in the cache functions, an attacker could inject arbitrary shell commands through malicious repository data containing shell metacharacters. The fix replaces `execSync()` with `execFileSync()` and tightens input sanitization on cache file paths.