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

medium

How Insufficient Password Hashing Cost Factor Happens in Node.js and How to Fix It

A bcrypt password hashing implementation in the User.js model was using a cost factor of 10, which falls below OWASP's 2024 recommendation of 12 for applications handling sensitive data. This fix upgrades the salt rounds from 10 to 12, increasing the computational work required to crack passwords by approximately 4x, significantly improving protection against brute-force attacks on this e-commerce platform.

high

How Arbitrary Code Execution via Template Imports Happens in JavaScript (lodash) and How to Fix It

A high-severity arbitrary code execution vulnerability (CVE-2026-4800) was discovered in lodash's template function, specifically in how it handles the `imports` option with untrusted input. The fix upgrades lodash from version 4.17.21 to 4.18.0 in the project's `package.json` and `yarn.lock`, eliminating the attack surface where crafted template imports could execute arbitrary code on the server.

critical

How Server-Side Request Forgery (SSRF) happens in Node.js IP address parsing and how to fix it

A critical SSRF vulnerability (CVE-2026-69192) was discovered in the ip-address npm package version 10.2.0, which could allow attackers to bypass IP address validation and access internal services. The fix upgrades the dependency to version 10.3.1, which properly handles edge cases in IP address parsing that previously allowed trust-boundary bypasses.

critical

How Sensitive Data Exposure happens in Python web applications and how to fix it

A critical sensitive data exposure vulnerability was discovered in `nodes/google_gemini.py` where the Google Gemini API key was returned in plaintext through a web endpoint. The fix masks the token in API responses, preventing credential theft from any client that queries the token endpoint. This protects downstream users of this Node.js library from unauthorized access to their Google Gemini services.

high

How Authentication Bypass happens in Next.js App Router with Turbopack and how to fix it

A critical authentication bypass vulnerability (CVE-2026-64642) was discovered in Next.js versions prior to 16.2.11, specifically affecting App Router applications using Turbopack with a single locale configuration. This vulnerability allowed attackers to bypass middleware and proxy protections, potentially gaining unauthorized access to protected routes and resources that should have been secured by authentication checks.

critical

How SQL Injection Happens in CSV-to-SQL Converters and How to Fix It

A critical SQL injection vulnerability was discovered in the `csv2sql()` function in `src/data/converter/csv.js`, where CSV data and table names were directly interpolated into SQL INSERT statements without sanitization. The fix implements input validation through identifier sanitization and proper value escaping, eliminating the attack surface while preserving legitimate functionality.