Back to Blog
critical SEVERITY6 min read

How hardcoded API keys happen in Node.js client-side JavaScript and how to fix it

A critical hardcoded API key for ipregistry.co was discovered embedded as a fallback value in `src/utils.js` at line 65 of a Node.js library. This key (`f8n4kqe8pv4kii`) was visible to anyone inspecting the JavaScript bundle, allowing unauthorized use of the service. The fix removes the hardcoded fallback, requiring callers to explicitly provide their own API key.

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

Answer Summary

This vulnerability is a hardcoded API key (CWE-798) in a Node.js library's `src/utils.js` file, where an ipregistry.co credential was embedded as a fallback value in client-side JavaScript. The fix removes the hardcoded key entirely from line 65, eliminating the `apiKey = apiKey || "f8n4kqe8pv4kii"` fallback pattern so that callers must supply their own key via configuration or environment variables.

Vulnerability at a Glance

cweCWE-798
fixRemove the hardcoded fallback key, requiring explicit key injection via environment variables or configuration
riskExposed API key allows unauthorized access to ipregistry.co services and potential abuse at the key owner's expense
languageJavaScript (Node.js)
root causeAPI key used as inline fallback value in client-side code (`apiKey = apiKey || "f8n4kqe8pv4kii"`)
vulnerabilityHardcoded API Key / Credentials

Introduction

In a Node.js library used by downstream consumers, we discovered a critical hardcoded API key vulnerability in src/utils.js at line 65. The ipregistry.co API key f8n4kqe8pv4kii was embedded directly in the source code as a fallback value using the pattern apiKey = apiKey || "f8n4kqe8pv4kii". Because this library ships as client-side JavaScript, anyone who opened their browser's DevTools could extract this credential in seconds—no decompilation or reverse engineering required.

This matters because the library is a package consumed by other applications. Every downstream project that bundles this code inadvertently ships a third-party API key to their end users, creating a supply chain credential leak that scales with adoption.

The Vulnerability Explained

What's happening in the code

The utils object in src/utils.js contains an IP geolocation lookup function. Here's the vulnerable code:

// src/utils.js - BEFORE fix (line 62-68)
const utils = {
  // ... other methods
  lookupIp(ip, apiKey) {
    if (cache[ip]) {
      return cache[ip];
    }

    apiKey = apiKey || "f8n4kqe8pv4kii";  // ← HARDCODED KEY
    return fetch(`https://api.ipregistry.co/${ip}?key=${apiKey}`)
      .then((resp) => resp.json())
      .then((result) => {
        // ...
      });
  }
};

The line apiKey = apiKey || "f8n4kqe8pv4kii" acts as a "convenience" fallback: if no API key is passed to the function, it defaults to a hardcoded one. This is a classic anti-pattern in library development—providing a "just works" experience at the cost of security.

How an attacker exploits this

The exploitation is trivial:

  1. Open any web application that uses this library
  2. Open browser DevTools (F12 or Ctrl+Shift+I)
  3. Navigate to Sources tab and locate src/utils.js in the bundle (or search for "ipregistry")
  4. Copy the API key f8n4kqe8pv4kii

With the extracted key, an attacker can:

  • Abuse the ipregistry.co service under the key owner's account, consuming their API quota or racking up charges on a paid plan
  • Perform mass IP geolocation lookups for reconnaissance, spam campaigns, or scraping operations—all billed to the legitimate key owner
  • Trigger rate limits or account suspension for the key owner, causing denial of service for all legitimate users of the library

Why this is critical

This isn't just a theoretical risk. The key is:
- In production code (not test-only)
- In a client-side JavaScript bundle (fully visible to end users)
- In a library (multiplied across every downstream consumer)
- Used in a network request (the key travels in the URL query string, potentially logged by proxies)

The Fix

The fix is a single-line removal that eliminates the hardcoded fallback:

Before (vulnerable)

apiKey = apiKey || "f8n4kqe8pv4kii";
return fetch(`https://api.ipregistry.co/${ip}?key=${apiKey}`)

After (fixed)

return fetch(`https://api.ipregistry.co/${ip}?key=${apiKey}`)

Why this works

By removing line 65 entirely, the function no longer provides a fallback credential. If a caller doesn't pass an apiKey parameter, the value will be undefined, and the API call will fail with an authentication error from ipregistry.co. This is the correct behavior—it forces consumers to:

  1. Provide their own API key explicitly
  2. Load that key from a secure source (environment variable, server-side config, or secret manager)
  3. Take responsibility for their own credential management

The fix preserves the function's interface—apiKey is still a parameter—but removes the dangerous default. Existing tests pass because they either supply a key or mock the fetch call.

What about the exposed key?

Removing the key from source code is necessary but not sufficient. The key f8n4kqe8pv4kii should also be:
- Rotated on ipregistry.co's dashboard (the old key is compromised)
- Scrubbed from git history if the repository is public (using git filter-branch or BFG Repo-Cleaner)
- Monitored for unauthorized usage in ipregistry.co's analytics

Prevention & Best Practices

1. Never embed secrets in client-side code

Client-side JavaScript is inherently public. There is no way to hide a secret in a browser-delivered bundle. If you need to call a third-party API:

  • Use a server-side proxy: Your backend calls the API with the key, and your frontend calls your backend
  • Use environment variables: process.env.IPREGISTRY_API_KEY for server-side Node.js
  • Use build-time injection carefully: Tools like webpack's DefinePlugin can inject values, but they still end up in the bundle

2. Use secret scanning in CI/CD

Add pre-commit hooks and CI checks to catch secrets before they reach the repository:

# Example: GitHub Actions with gitleaks
- name: Scan for secrets
  uses: gitleaks/gitleaks-action@v2

3. Library design patterns

For library authors who need API keys:

// GOOD: Require explicit configuration
function createClient(config) {
  if (!config.apiKey) {
    throw new Error('API key is required. Get one at https://ipregistry.co');
  }
  // ...
}

// BAD: Hardcoded fallback
function createClient(config) {
  const apiKey = config.apiKey || "hardcoded-key-here";
  // ...
}

4. Reference standards

  • CWE-798: Use of Hard-coded Credentials
  • OWASP: Cryptographic Failures (A02:2021)
  • OWASP Secret Management Cheat Sheet: Guidance on secure credential storage and injection

Key Takeaways

  • The apiKey = apiKey || "f8n4kqe8pv4kii" pattern in src/utils.js turned a convenience feature into a credential leak—fallback values for secrets are never acceptable in client-side code.
  • Library authors bear extra responsibility: a hardcoded key in a library propagates to every downstream consumer's production bundle.
  • The ipregistry.co key f8n4kqe8pv4kii was extractable by any user with browser DevTools—no sophisticated tooling or reverse engineering needed.
  • Removing the fallback is the correct fix: failing loudly when no key is provided forces proper credential management by consumers.
  • The exposed key must be rotated immediately—removing it from code doesn't invalidate it on the service provider's side.

How Orbis AppSec Detected This

  • Source: The apiKey parameter in src/utils.js with a hardcoded string literal fallback "f8n4kqe8pv4kii" at line 65
  • Sink: The fetch() call to https://api.ipregistry.co/${ip}?key=${apiKey} which transmits the credential over the network
  • Missing control: No mechanism to load the API key from a secure external source (environment variable, secret manager, or server-side proxy); instead, a plaintext credential was embedded directly in distributable source code
  • CWE: CWE-798 — Use of Hard-coded Credentials
  • Fix: Removed the hardcoded fallback assignment apiKey = apiKey || "f8n4kqe8pv4kii" from line 65, requiring callers to explicitly provide their own API key

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 credentials remain one of the most common and most preventable security issues in modern software. In this case, a single line of "convenience" code—apiKey = apiKey || "f8n4kqe8pv4kii"—turned a Node.js library into a credential distribution mechanism, shipping an ipregistry.co API key to every end user of every application that consumed it.

The fix was simple: remove the fallback and let the function fail explicitly when no key is provided. But the lesson runs deeper. Library authors must design their APIs to require secure credential injection from the start, and every development team should have automated secret scanning in their CI pipeline to catch these issues before they reach production.

If you're working on a library or application that calls third-party APIs, audit your codebase today for fallback credential patterns. Your future self—and your API bill—will thank you.

References

Frequently Asked Questions

What is a hardcoded API key vulnerability?

A hardcoded API key vulnerability occurs when secret credentials are embedded directly in source code rather than being loaded from secure external sources like environment variables or secret managers. Anyone with access to the code—including end users via browser DevTools—can extract and misuse the key.

How do you prevent hardcoded API keys in JavaScript?

Use environment variables (e.g., `process.env.API_KEY`), server-side proxies, or secret management services to inject keys at runtime. Never embed keys as string literals in client-side JavaScript, as bundled code is always accessible to users.

What CWE is hardcoded credentials?

CWE-798: Use of Hard-coded Credentials. This covers any situation where credentials such as passwords, API keys, or cryptographic keys are embedded directly in source code.

Is code obfuscation enough to prevent API key exposure in JavaScript?

No. Obfuscation only makes extraction slightly harder but never prevents it. Determined attackers can deobfuscate code or intercept network requests to discover keys. The only safe approach is to never include secrets in client-side code.

Can static analysis detect hardcoded API keys?

Yes. Tools like Semgrep, GitLeaks, TruffleHog, and custom regex-based scanners can detect patterns matching API keys, tokens, and passwords in source code. They are most effective when combined with entropy-based detection for high-randomness strings.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #77

Related Articles

critical

How unauthenticated API access happens in Node.js Express endpoints and how to fix it

The `/api/translate` endpoint in `api/translate.js` was publicly accessible without any authentication, allowing anonymous users to freely invoke paid Anthropic Claude or Google Translate API calls. This critical vulnerability exposed the application to API cost abuse, quota exhaustion, and potential data exfiltration. A targeted fix adds a shared-secret header check before any translation logic executes.

high

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

A high-severity vulnerability (CVE-2026-42033) in axios 1.13.6 allowed attackers to hijack HTTP transport behavior through prototype pollution, potentially redirecting sensitive requests to attacker-controlled servers. The fix upgrades axios to 1.15.1 and proxy-from-env to 2.1.0 in a Node.js sandbox base image used in production, eliminating the attack vector.

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 session fixation happens in PHP OAuth login handlers and how to fix it

A session fixation vulnerability in `trunk/web/login_weibo.php` allowed attackers to hijack authenticated user sessions by pre-setting a victim's PHP session ID before they logged in via Weibo OAuth. The fix was a single, critical call to `session_regenerate_id(true)` inserted immediately before assigning the authenticated user's ID to the session. Left unpatched, this vulnerability could have given an attacker full access to any account whose Weibo OAuth login they could observe or influence.