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

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.

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #1

Related Articles

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.

critical

How Remote Code Execution Happens in Handlebars Template Compilation and How to Fix It

CVE-2026-33937 is a critical remote code execution vulnerability in Handlebars.js that allows attackers to execute arbitrary code by passing maliciously crafted Abstract Syntax Tree (AST) objects to the compile() function. The vulnerability was patched in version 4.7.9, and we've upgraded to protect against this threat vector.