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 insecure update manifest parsing happens in C++ UpdateHelper.cpp and how to fix it

TrafficMonitor's software update mechanism in `UpdateHelper.cpp` fetched and parsed update manifests from remote servers without validating the version string or enforcing trusted download URLs, leaving users exposed to man-in-the-middle (MITM) attacks. An attacker on the same network could intercept the update channel and inject a malicious binary under a crafted version string or an HTTP download link pointing to attacker-controlled infrastructure. The fix adds strict version-string sanitizati

high

How integer overflow in malloc happens in C bipartite matching and how to fix it

A high-severity integer overflow vulnerability was discovered in the bipartite matching algorithm implementation where unchecked multiplication operations for memory allocation could wrap around, causing undersized buffer allocations and subsequent heap overflow. The fix replaces vulnerable `malloc(sizeof(int) * V)` patterns with safe `calloc(V, sizeof(int))` calls and adds proper bounds validation to prevent exploitation.

high

How integer truncation heap overflow happens in C++ UEFI ACPI parsing and how to fix it

A high-severity integer truncation vulnerability was discovered in `Mobility.Uefi.Acpi.cpp` where heap allocation sizes were stored in a 16-bit integer (`MO_UINT16`), causing silent truncation when the computed size exceeded 65535 bytes. This led to undersized heap allocations followed by out-of-bounds writes, exploitable by an attacker who can influence ACPI SRAT table contents in virtualized environments. The fix promotes the size variable to `MO_UINTN` (platform-native width) to prevent trunc

high

How path traversal happens in Ruby YARD server and how to fix it

A high-severity path traversal vulnerability (CVE-2026-41493) in YARD versions prior to 0.9.42 allowed attackers to read arbitrary files from servers running `yard server`. This fix upgrades the yard gem from 0.9.26 to 0.9.42 in the Gemfile and Gemfile.lock, closing a dangerous information disclosure vector that could expose configuration files, credentials, and source code.

high

How buffer overflow via sprintf() happens in C networking code and how to fix it

A high-severity buffer overflow vulnerability was discovered in `profile.c` where `sprintf()` was used to format server addresses without any bounds checking. An attacker who could influence the `SERVER_BASE_PORT` value or trigger integer overflow in the port calculation could write beyond the `server_address` buffer. The fix replaces `sprintf()` with `snprintf()` using explicit buffer size limits at both call sites (lines 99 and 220).

critical

How integer overflow in buffer size calculation happens in C and how to fix it

A critical integer overflow vulnerability was discovered in the `nsh_setvar()` function in `nshlib/nsh_vars.c`, where the buffer size calculation `newsize = pstate->varsz + varlen` could wrap around, causing a heap buffer overflow. The fix adds overflow checking before the addition, preventing attackers with shell access from corrupting memory by setting variables with crafted names and values.