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:
- Right-click and "View Page Source"
- Open browser Developer Tools (F12) and inspect the Sources tab
- 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:
- Extract the key: Open
js/douban.jsin browser DevTools, search for "apikey", and copy0ac44ae016490db2204ce0a042db2916 - Abuse the API quota: Make unlimited requests to Douban's API using the stolen key, potentially exhausting rate limits for legitimate users
- Impersonate the application: Use the key to access Douban API endpoints, potentially accessing data or functionality meant only for this application
- 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:
- No credential is exposed in client-side code
- The API integration breaks intentionally until a proper server-side solution is implemented
- 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:
- Generate a new API key in the service's dashboard
- Update your secure backend configuration
- Revoke the old key
- Monitor for unauthorized usage
Key Takeaways
- The
miniapp_apikeyindouban.jswas 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_requestfunction 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 tominiapp_apikeyinjs/douban.js:697 - Sink: The
query.apikey = miniapp_apikeyassignment in theminiapp_requestfunction, 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.