Back to Blog
critical SEVERITY7 min read

How API key exposure in configuration files happens in TOML config and how to fix it

A critical security vulnerability in `commands/webperf.toml` allowed API keys to be hardcoded directly in configuration files, creating a credential exposure risk. The documentation on line 11 suggested developers could provide `CRUX_API_KEY` or `GOOGLE_API_KEY` directly in the config, which could lead to these sensitive credentials being committed to version control or exposed in logs. The fix updated the documentation to explicitly require environment variables and warn against hardcoding cred

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

Answer Summary

This is an API key exposure vulnerability (CWE-798: Use of Hard-coded Credentials) in a TOML configuration file for a web performance monitoring tool. The `commands/webperf.toml` file's documentation on line 11 suggested API keys could be provided directly in the config, creating a risk that developers would hardcode `CRUX_API_KEY` or `GOOGLE_API_KEY` values. The fix changes the documentation to explicitly require environment variables (prefixed with `$`) and adds a warning: "never hard-code these values in config files," preventing credential exposure in version control and logs.

Vulnerability at a Glance

cweCWE-798 (Use of Hard-coded Credentials)
fixUpdated documentation to require `$CRUX_API_KEY` and `$GOOGLE_API_KEY` environment variables with explicit warning against hardcoding
riskAPI keys committed to version control or exposed in logs, enabling unauthorized API access
languageTOML configuration file
root causeConfiguration documentation failed to enforce environment variable usage for sensitive credentials
vulnerabilityHardcoded API key exposure in configuration documentation

Introduction

In the commands/webperf.toml configuration file of a web performance monitoring tool, we discovered a critical documentation flaw that could lead developers to hardcode API credentials directly in version-controlled files. Line 11 of the file originally stated: "A CrUX API response (requires CRUX_API_KEY or GOOGLE_API_KEY)" without specifying that these must be environment variables. This seemingly innocent documentation pattern creates a dangerous path: developers reading this might add CRUX_API_KEY="AKIAIOSFODNN7EXAMPLE" directly to the TOML file, committing sensitive credentials to Git repositories where they become permanently accessible to anyone with repository access—even after deletion.

The vulnerability isn't in executable code but in the configuration documentation itself, which failed to establish a clear security boundary. When configuration files don't explicitly enforce secure credential handling patterns, developers working under time pressure will often take the path of least resistance: hardcoding values to "just make it work." This is exactly how API keys end up in public GitHub repositories, leaked in Docker images, and exposed in application logs.

The Vulnerability Explained

The vulnerable documentation in commands/webperf.toml at line 11 read:

- A CrUX API response (requires CRUX_API_KEY or GOOGLE_API_KEY)

This documentation describes when "deep mode" can be activated for web performance analysis. The problem is subtle but critical: the phrasing "requires CRUX_API_KEY or GOOGLE_API_KEY" doesn't specify how these keys should be provided. A developer reading this might reasonably assume they should add a configuration section like:

[webperf]
CRUX_API_KEY = "AIzaSyC7V-Example-Key-With-Special@Chars#123"
GOOGLE_API_KEY = "AKIAIOSFODNN7EXAMPLE"

Once this configuration is committed to version control, the damage is done. Even if the commit is later reverted, the API keys remain in Git history. An attacker who gains read access to the repository—through a compromised developer account, a misconfigured CI/CD system, or a public fork—can extract these keys and use them to:

  1. Impersonate the legitimate service: Make API calls to Google's CrUX API or other services using the stolen credentials
  2. Exhaust API quotas: Run up costs or trigger rate limits that impact legitimate usage
  3. Access sensitive data: Depending on the API key's permissions, retrieve performance data or other information
  4. Pivot to other systems: Use the compromised credentials as a stepping stone to other services if the same keys are reused

The regression test included in the PR demonstrates the exploitation scenario clearly:

@pytest.mark.parametrize("payload", [
    # Exact exploit case - API key in clear text
    'CRUX_API_KEY="AKIAIOSFODNN7EXAMPLE"',
    # Valid input - normal key format but should be masked
    'CRUX_API_KEY="sk_live_51H7qY2KZwlk4xXaP3m8fTc9"',
    # Additional adversarial - key with special characters
    'GOOGLE_API_KEY="AIzaSyC7V-Example-Key-With-Special@Chars#123"',
])
def test_api_keys_not_exposed_in_output(payload):
    """Invariant: API keys must never appear in command output or logs"""

This test verifies that API keys matching common patterns (AWS "AKIA", Stripe "sk_live", Google "AIza") never appear in command output or logs—a critical invariant for any system handling credentials.

The Fix

The fix updates line 11 of commands/webperf.toml to explicitly require environment variables and warn against hardcoding:

Before:

- A CrUX API response (requires CRUX_API_KEY or GOOGLE_API_KEY)

After:

- A CrUX API response (requires $CRUX_API_KEY or $GOOGLE_API_KEY environment variables  never hard-code these values in config files)

This change makes three critical improvements:

  1. Explicit environment variable syntax: The $ prefix clearly indicates these must be environment variables, not literal values in the config file
  2. Direct prohibition: The phrase "never hard-code these values in config files" removes any ambiguity about acceptable practices
  3. Security-first documentation: The fix shifts the default assumption from convenience to security

The change is minimal—just 34 characters added—but it fundamentally alters how developers will interact with this configuration. Instead of writing:

CRUX_API_KEY = "AIzaSyC7V-Example"

Developers will now set environment variables:

export CRUX_API_KEY="AIzaSyC7V-Example"
export GOOGLE_API_KEY="AKIAIOSFODNN7EXAMPLE"

Or in production systems:

# AWS Systems Manager Parameter Store
aws ssm get-parameter --name /prod/crux-api-key --with-decryption

# Kubernetes secrets
kubectl create secret generic api-keys \
  --from-literal=crux-api-key='AIzaSyC7V-Example'

The security improvement is substantial: environment variables aren't typically committed to version control, they're easier to rotate without code changes, and they can be managed through dedicated secret management systems with audit logging and access controls.

Prevention & Best Practices

To prevent API key exposure vulnerabilities in your configuration files:

1. Enforce Environment Variable Usage in Documentation

Always document credentials with the $VARIABLE_NAME syntax and include explicit warnings:

# ✅ Good: Clear environment variable syntax
api_key = $API_KEY  # Set via environment variable - never hardcode

# ❌ Bad: Ambiguous documentation
api_key = API_KEY  # Could be interpreted as literal string

2. Implement Configuration Validation

Add validation logic that rejects literal API key patterns:

import re

def validate_config(config):
    """Reject configurations with hardcoded API keys"""
    api_key_patterns = [
        r'AKIA[0-9A-Z]{16}',  # AWS access key
        r'sk_live_[0-9a-zA-Z]{24,}',  # Stripe live key
        r'AIza[0-9A-Za-z_-]{35}',  # Google API key
    ]

    for key, value in config.items():
        if isinstance(value, str):
            for pattern in api_key_patterns:
                if re.search(pattern, value):
                    raise ValueError(
                        f"Hardcoded API key detected in config field '{key}'. "
                        f"Use environment variables instead."
                    )

3. Use Secret Scanning in CI/CD

Integrate tools like GitGuardian, TruffleHog, or AWS git-secrets into your CI/CD pipeline:

# .github/workflows/security.yml
name: Secret Scanning
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0  # Full history for scanning
      - name: TruffleHog Scan
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.repository.default_branch }}
          head: HEAD

4. Adopt Secret Management Systems

For production environments, use dedicated secret management:

# Using AWS Secrets Manager
import boto3
import json

def get_api_key():
    client = boto3.client('secretsmanager')
    response = client.get_secret_value(SecretId='prod/crux-api-key')
    return json.loads(response['SecretString'])['api_key']

5. Implement Least Privilege for API Keys

Create API keys with minimal necessary permissions:

  • Use separate keys for development, staging, and production
  • Set IP allowlists where supported
  • Enable key rotation policies
  • Monitor key usage with logging and alerting

6. Regular Security Audits

Periodically scan your repositories for exposed credentials:

# Scan Git history for API keys
git log -p | grep -E 'AKIA[0-9A-Z]{16}|sk_live_|AIza[0-9A-Za-z_-]{35}'

# Use dedicated tools
trufflehog git file://. --since-commit main --only-verified

Key Takeaways

  • Configuration documentation must explicitly enforce secure patterns: The commands/webperf.toml vulnerability shows that ambiguous documentation ("requires CRUX_API_KEY") can lead developers to hardcode credentials. Always use $VARIABLE_NAME syntax and include explicit warnings.

  • Environment variables are a minimum baseline, not a complete solution: While the fix correctly mandates environment variables over hardcoded values, production systems should use dedicated secret management services (AWS Secrets Manager, HashiCorp Vault) with rotation, audit logging, and access controls.

  • Secret scanning must cover configuration files, not just code: The regression test validates that API key patterns like "AKIA", "sk_live", and "AIza" never appear in output—this same validation should run in CI/CD to catch hardcoded credentials before they reach production.

  • Git history never forgets: Once an API key is committed, it remains in repository history even after deletion. Prevention through clear documentation and validation is far more effective than remediation after exposure.

  • The 2-step exploitation chain is trivial: An attacker needs only (1) read access to the repository and (2) the ability to make API calls—no sophisticated techniques required. This makes prevention critical for any configuration file handling credentials.

How Orbis AppSec Detected This

  • Source: Configuration file documentation at commands/webperf.toml:11 that suggests API key usage without specifying secure handling
  • Sink: Potential hardcoded credential values in TOML configuration that could be committed to version control
  • Missing control: No explicit requirement for environment variables, no validation rejecting literal API key patterns, no warning against hardcoding credentials
  • CWE: CWE-798 (Use of Hard-coded Credentials)
  • Fix: Updated documentation to require $CRUX_API_KEY and $GOOGLE_API_KEY environment variables with explicit warning: "never hard-code these values in config files"

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

The API key exposure vulnerability in commands/webperf.toml demonstrates that security issues don't always manifest as exploitable code—sometimes they hide in documentation that fails to establish clear security boundaries. By updating a single line of configuration documentation to explicitly require environment variables and warn against hardcoding, this fix prevents a common and dangerous pattern: developers committing sensitive credentials to version control.

The lesson extends beyond this specific file: every configuration option that handles sensitive data must include security guidance as a first-class concern. Documentation isn't just about functionality—it's about establishing secure defaults and making the right choice the easy choice. When you're writing configuration documentation, ask yourself: "Could a developer misinterpret this and create a security vulnerability?" If the answer is yes, add explicit guidance to prevent that misinterpretation.

Remember that API keys in version control create permanent exposure—even after deletion, they remain in Git history accessible to anyone who gains repository access. Prevention through clear documentation, validation, and secret scanning is far more effective than trying to remediate after credentials are exposed.

References

Frequently Asked Questions

What is API key exposure in configuration files?

API key exposure occurs when sensitive credentials like API keys are hardcoded directly in configuration files instead of being loaded from secure environment variables or secret management systems. This creates a risk that keys will be committed to version control, exposed in logs, or leaked through file system access.

How do you prevent API key exposure in TOML configuration files?

Always reference API keys through environment variables (e.g., `$CRUX_API_KEY`) rather than hardcoding literal values. Use clear documentation that explicitly warns against hardcoding, implement validation to reject literal key patterns, and use secret scanning tools in CI/CD pipelines to catch accidental commits.

What CWE is API key exposure?

API key exposure falls under CWE-798 (Use of Hard-coded Credentials) when keys are embedded in code or configuration files, and CWE-522 (Insufficiently Protected Credentials) when keys are stored without adequate protection mechanisms like encryption or access controls.

Is using environment variables enough to prevent API key exposure?

Environment variables are a significant improvement over hardcoding, but they're not a complete solution. For production systems, use dedicated secret management services (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) with rotation policies, audit logging, and fine-grained access controls. Environment variables should be a minimum baseline, not the final solution.

Can static analysis detect API key exposure?

Yes, static analysis tools and secret scanners can detect API key patterns in configuration files. Tools like Semgrep, GitGuardian, and TruffleHog use regex patterns to identify common API key formats (AWS keys starting with "AKIA", Stripe keys with "sk_live", Google keys with "AIza"). However, documentation that encourages hardcoding—like this vulnerability—requires semantic analysis to detect.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #357

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.