Back to Blog
critical SEVERITY7 min read

How Hardcoded Secrets Compromise Authentication in JavaScript and How to Fix It

A critical vulnerability in `Tool/QuantumultX/Rewrite/RRSP.js` exposed hardcoded API authentication credentials—a TOKEN and UMID device identifier—directly in source code. Anyone with repository access could extract these credentials to impersonate the legitimate user and gain full account access to the RRTV API service. The fix replaced hardcoded secrets with empty placeholders, forcing users to manually configure credentials through secure channels.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published September 9, 2026•Reviewed September 9, 2026

Answer Summary

Hardcoded Secrets (CWE-798) in JavaScript occurs when authentication credentials like API tokens and device identifiers are embedded directly in source code. In RRSP.js, the TOKEN "rrtv-483e4fb0a5e14f0ef6e632f36db9c59704857993" and UMID "C6CFE97D-A15C-4FE0-8666-FB0036C5E32A" were visible to anyone accessing the repository, allowing credential theft and account takeover. The fix removes hardcoded values and requires manual configuration, eliminating the exposed credentials from version control.

Vulnerability at a Glance

cweCWE-798 (Use of Hard-Coded Credentials)
fixReplace hardcoded credentials with empty string defaults and document manual configuration requirement
riskComplete account compromise; credential theft; API impersonation; unauthorized access to user data and services
languageJavaScript
root causeAuthentication credentials embedded directly in source code instead of being externalized
vulnerabilityHardcoded Secrets / Credential Exposure

How Hardcoded Secrets Compromise Authentication in JavaScript and How to Fix It

Introduction

In the Tool/QuantumultX/Rewrite/RRSP.js file, a critical vulnerability exposed authentication credentials directly in source code. The USER_CONFIG object on lines 27-28 contained a hardcoded TOKEN (rrtv-483e4fb0a5e14f0ef6e632f36db9c59704857993) and UMID device identifier (C6CFE97D-A15C-4FE0-8666-FB0036C5E32A) used to authenticate with the RRTV API service. This vulnerability created a 2-step attack chain: an attacker could extract these credentials from the public repository and immediately use them to make authenticated API requests to api.rrmj.plus, gaining complete access to the user's account.

For developers working with API integrations and configuration management, this vulnerability illustrates a fundamental security principle: credentials must never live in code. Even in "private" scripts or seemingly internal tools, hardcoded secrets are a liability the moment code is shared, archived, or exposed.

The Vulnerability Explained

What Made This Code Vulnerable?

The vulnerable code in RRSP.js looked like this:

// 配置 
let USER_CONFIG = {
    TOKEN: "rrtv-483e4fb0a5e14f0ef6e632f36db9c59704857993", 
    UMID: "C6CFE97D-A15C-4FE0-8666-FB0036C5E32A",  
    PLAYER_Code: "SenPlayer", 
    CustomScheme: "" 
};

The specific problem:

  1. Lines 27-28 contain literal credential strings embedded in configuration that will be read into memory every time the script executes
  2. The TOKEN follows a predictable pattern (rrtv- prefix), making it easily identifiable as an authentication secret
  3. The UMID is a UUID format, another recognizable pattern that credential scanners detect
  4. These values are committed to the repository, making them accessible to anyone with clone/fork permissions—forever in Git history unless actively purged
  5. No environment variable or external configuration mechanism exists to override these defaults, forcing users to either modify source code or accept the exposed credentials

How This Could Be Exploited

An attacker following this 2-step chain:

  1. Discovery: Clone or fork the public repository containing RRSP.js, scan the file, and extract the TOKEN and UMID strings from lines 27-28
  2. Exploitation: Use these credentials in HTTP requests to api.rrmj.plus:
    javascript fetch('https://api.rrmj.plus/endpoint', { headers: { 'Authorization': `Bearer ${TOKEN}`, 'X-UMID': UMID } })
    The API would recognize these credentials as valid and authenticate the request as the legitimate user, granting full access to account data, content library, viewing history, and any other RRTV API functionality

Real-World Impact for RRSP.js

  • Account Takeover: The attacker gains full control over the RRTV account associated with these credentials
  • Data Breach: Access to all content watched, bookmarks, preferences, and personal viewing history
  • Service Abuse: Using the account to stream premium content without authorization, potentially triggering false fraud alerts or account suspension for the legitimate user
  • Persistence: Without rotating credentials, the compromise is persistent until the legitimate user manually changes their token
  • Supply Chain Risk: If this script is shared across teams or embedded in other tools, the compromise spreads to all downstream users

The Fix

What Changed?

The pull request replaced the hardcoded credentials with empty string defaults and added inline comments instructing users to manually fill in values:

// BEFORE (vulnerable)
let USER_CONFIG = {
    TOKEN: "rrtv-483e4fb0a5e14f0ef6e632f36db9c59704857993", 
    UMID: "C6CFE97D-A15C-4FE0-8666-FB0036C5E32A",  
    PLAYER_Code: "SenPlayer", 
    CustomScheme: "" 
};

// AFTER (fixed)
let USER_CONFIG = {
    TOKEN: "", //手动填写频道更新的token
    UMID: "",  //手动填写..
    PLAYER_Code: "SenPlayer", 
    CustomScheme: "" 
};

Why this specific change works:

  1. Empty defaults prevent automatic credential exposure: No credentials live in the repository or Git history
  2. Credentials remain outside version control: Users manually configure their own TOKEN and UMID at runtime or through external configuration
  3. Shifts responsibility to users: The script won't function without explicit user configuration, preventing accidental use of leaked credentials
  4. No hardcoded patterns to detect: Secret scanning tools won't flag empty strings, reducing false positives
  5. Eliminates 2-step attack chain: Even if an attacker accesses the repository, no valid credentials exist to extract

How the Fix Solves This Specific Problem

Before the fix:
- Credentials: Always present, always exploitable, always in Git history
- Exploit complexity: Trivial (copy-paste from source)
- Blast radius: Everyone who cloned the repo

After the fix:
- Credentials: Never stored in code or Git
- Exploit complexity: Impossible from repository alone; attacker must compromise the user's local configuration
- Blast radius: Limited to individual user's local machine

The fix follows the principle of least privilege in configuration: the script ships with no secrets, and users must consciously provide them during setup.

Prevention & Best Practices

To prevent this vulnerability in similar code:

1. Use Environment Variables

let USER_CONFIG = {
    TOKEN: process.env.RRTV_TOKEN || "", 
    UMID: process.env.RRTV_UMID || "",  
    PLAYER_Code: "SenPlayer", 
    CustomScheme: "" 
};

Users set export RRTV_TOKEN=<token> before running the script.

2. Use External Configuration Files (Outside .gitignore)

const fs = require('fs');
const path = require('path');

// Load from ~/.config/rrsp/config.json
const configPath = path.join(process.env.HOME, '.config/rrsp/config.json');
const userConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));

Add ~/.config/rrsp/config.json to .gitignore.

3. Implement Secret Scanning Pre-Commit Hooks

Use tools like TruffleHog or detect-secrets to block commits containing credential patterns:

npm install --save-dev @trufflesecurity/trufflehog
# Or
npm install --save-dev detect-secrets

4. Use Semgrep Rules to Catch Hardcoded Secrets

Deploy Semgrep rule javascript.lang.security.hardcoded-secrets to catch patterns like:

TOKEN: "[a-f0-9]{40,}"  # 40+ hex chars (common token format)

5. Follow OWASP Guidelines

Reference OWASP's Secrets Management Cheat Sheet for best practices on credential storage and rotation.

6. Rotate Exposed Credentials Immediately

If hardcoded credentials are ever committed, they must be assumed compromised. Rotate the TOKEN and UMID in the RRTV API settings immediately.

7. Audit Git History

Use git log -S "rrtv-" to find all commits containing the leaked token pattern and ensure they're removed from all branches.

Key Takeaways

  • Hardcoded tokens in JavaScript configuration objects are trivial to extract and exploit: The USER_CONFIG object in RRSP.js lines 27-28 exposed credentials directly to anyone with repository access—no decryption or reverse engineering needed.

  • Credential patterns are predictable and easily scannable: The rrtv- prefix and UUID format in the UMID made this vulnerability detectable by automated secret scanning tools, showing why secrets should be externalized before code review.

  • Empty string defaults with documentation shift security responsibility: Replacing hardcoded values with "" and comments forces users to consciously configure credentials, preventing accidental deployment of exposed secrets.

  • 2-step account takeover chains are high-risk but preventable: This vulnerability required only repository access + credential usage—a trivial 2-step exploit that environment variables or secret managers completely eliminate.

  • Version control history is permanent: Deleting hardcoded secrets from the current branch isn't enough; they persist in Git history unless actively purged with tools like git-filter-repo, so prevention at commit time is essential.

How Orbis AppSec Detected This

Orbis AppSec identified this vulnerability through automated secret pattern analysis:

  • Source: Configuration object USER_CONFIG on lines 27-28 of Tool/QuantumultX/Rewrite/RRSP.js containing hardcoded credential literals
  • Sink: Direct assignment of sensitive strings to TOKEN and UMID properties without external sourcing or sanitization
  • Missing control: No environment variable lookup, no external config file loading, no secret manager integration—credentials embedded directly in code
  • CWE: CWE-798: Use of Hard-Coded Credentials — sensitive authentication information stored in source code accessible to attackers with code repository access
  • Fix: Replaced hardcoded token string "rrtv-483e4fb0a5e14f0ef6e632f36db9c59704857993" and UMID "C6CFE97D-A15C-4FE0-8666-FB0036C5E32A" with empty defaults (""), eliminating credentials from version control and requiring manual user configuration

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 secrets in JavaScript configuration files represent one of the easiest vulnerabilities to exploit and one of the most damaging once compromised. The RRSP.js vulnerability demonstrates that even in specialized or internal tools, credentials embedded in source code create an immediate account takeover risk.

The fix—replacing hardcoded values with empty defaults—is simple but requires discipline in your development workflow. Combined with environment variables, external configuration management, and automated secret scanning, this approach eliminates the vulnerability class entirely.

For your own projects:
1. Audit your codebase for hardcoded secrets using git log -S and Semgrep
2. Implement .gitignore rules and pre-commit hooks to prevent future commits
3. Use environment variables or secret managers for all credentials
4. Rotate any exposed credentials immediately
5. Remove secrets from Git history using git-filter-repo

Secure authentication starts with keeping credentials out of code. Make that your first principle, and you'll prevent vulnerabilities before they become incidents.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #2

Related Articles

critical

redmine_drawio View Hook Inlines Base64 Redmine API Keys

The Redmine drawio plugin's body-bottom view listener embedded the logged-in user's Redmine REST API key into client-side JavaScript on every wiki and issue page, "protected" only by Base64 encoding of the reversed string. Any script on the page — or anyone with browser developer tools, a cached copy of the HTML, or a proxy log — could decode it in one line and act as that user through the Redmine REST API. The fix removes the embedded credential from the rendered page entirely; the plugin's dia

critical

Yandex Translate API Key Leaked via URL Query Parameter

The `translateYandex()` helper built its request URL by interpolating the caller-supplied API key directly into the query string, meaning every call leaked the credential into server access logs, proxy logs, and any Referer header sent by intermediaries. The fix switches the request from a GET with the key in the URL to a POST with the key in the request body via `URLSearchParams`, removing the credential from any URL-logging surface entirely.

critical

Google Generative AI Keys Exposed in Client-Side Fetch URLs

A client-side AI model discovery utility was embedding Google Generative AI API keys directly in fetch request URLs, making them visible to any user inspecting network traffic or browser DevTools. The fix moves the key from the URL query parameter to a secure HTTP header, eliminating exposure while maintaining API authentication.

critical

How credential leakage through console logging happens in JavaScript browser extensions and how to fix it

A browser extension's `src/background/credentials.js` printed the full Strava authentication cookie string — including a signed JWT and CloudFront-Signature values — straight into the extension console via `console.debug`. Anyone who could open DevTools on the background page (or any tooling that scraped the console) could copy a live session and impersonate the user. The fix replaces the credential payload in both log statements with `Boolean(credentials)` and strips a realistic-looking JWT out

critical

How API Key Exposure in Request Bodies happens in React and how to fix it

The Chatbot component in gitforme was transmitting Azure OpenAI API keys inside JSON request bodies, causing them to be logged by servers, proxies, and middleware. By moving the apiKey from requestBody.apiKey to an Authorization header, credentials are now protected from persistence in generic request logging infrastructure.

critical

proxy-addr 2.0.7 IP Spoofing: CVE-2026-90711 Trust Bypass

A critical vulnerability in proxy-addr 2.0.7 allowed attackers to spoof client IP addresses by manipulating X-Forwarded-For headers when the trust chain evaluation contained specific misconfigurations. The fix in version 2.0.8 hardens the trust evaluation logic to prevent IP address falsification in Express.js applications relying on this common middleware dependency.