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

critical

How arbitrary code execution via injected protobuf definition type fields happens in Node.js and how to fix it

A critical arbitrary code execution vulnerability (CVE-2026-41242) was discovered in protobufjs versions prior to 7.5.5 and 8.0.1, allowing attackers to inject malicious code through crafted protobuf definition type fields. The fix upgrades the dependency from the vulnerable version 6.11.4 to 7.5.5, which properly sanitizes type field inputs during protobuf parsing. This vulnerability is especially dangerous because protobufjs is widely used in Node.js applications for serialization, meaning a s

high

How command injection happens in Node.js child_process and how to fix it

A high-severity command injection vulnerability was discovered in `bootstrap.js` at line 34, where the `exec()` function was used to run shell commands constructed from a `folder` variable. By replacing `exec()` with `execFile()` and passing arguments as an array, the fix eliminates the shell interpolation entirely, closing the door on command injection attacks that could have affected all downstream consumers of this Node.js library.

high

How unsafe pickle deserialization happens in NumPy's np.load() and how to fix it

A high-severity arbitrary code execution vulnerability was discovered in `tools/ardy-engine/retarget.py` where `np.load()` was called with `allow_pickle=True`, enabling attackers to embed malicious pickle payloads in `.npz` files. The fix was a single-character change—switching `allow_pickle=True` to `allow_pickle=False`—that eliminates the deserialization attack vector while preserving the file's legitimate array data loading functionality.

high

How SSRF and Credential Leakage via Absolute URLs happens in axios and how to fix it

A high-severity vulnerability (CVE-2025-27152) in axios versions prior to 1.8.2 allowed Server-Side Request Forgery (SSRF) attacks and credential leakage when making HTTP requests with absolute URLs. This vulnerability was fixed by upgrading from axios 1.7.4 to 1.8.2 in both package.json and package-lock.json, eliminating the attack vector that could have exposed authentication tokens and enabled unauthorized server-side requests.

high

How pickle-based arbitrary code execution happens in PyTorch and how to fix it

A high-severity arbitrary code execution vulnerability was discovered in `scripts/export_joyvasa_audio.py` where `torch.load()` was called with `weights_only=False`, allowing any pickle-serialized Python object — including malicious code — to execute during checkpoint loading. The fix switches to `weights_only=True` and explicitly allowlists only the two non-standard classes the checkpoint actually requires: `argparse.Namespace` and `pathlib.PosixPath`. This closes a real code execution path tha

critical

How WebSocket protocol length header abuse happens in Node.js and how to fix it

A critical vulnerability (CVE-2026-54466) in websocket-driver versions prior to 0.7.5 allows attackers to corrupt WebSocket messages by manipulating protocol length headers. This can lead to data integrity issues, denial of service, or potentially arbitrary code execution in affected Node.js applications. The fix involves upgrading the websocket-driver dependency to version 0.7.5.