HIGH command injectionapi keys

Command Injection with Api Keys

How Command Injection Manifests in Api Keys

Command injection in API keys typically occurs when untrusted input from API keys is used to construct shell commands or execute system-level operations. This vulnerability is particularly dangerous because API keys often grant programmatic access to external services, creating opportunities for attackers to execute arbitrary commands on the server or the external service itself.

The most common pattern involves API keys being concatenated into command strings without proper sanitization. For example, when an API key is passed to a subprocess call or shell command, an attacker can craft a key containing shell metacharacters that break out of the intended command context.

// Vulnerable pattern in Node.js using child_process
const { exec } = require('child_process');
const apiKey = req.query.apiKey;
exec(`curl -X POST https://api.example.com/data -H "Authorization: Bearer ${apiKey}"`, (err, stdout, stderr) => {
  console.log(stdout);
});

In this example, if an attacker provides an API key like validkey"; rm -rf /; echo ", the command becomes:

curl -X POST https://api.example.com/data -H "Authorization: Bearer validkey"; rm -rf /; echo "

This executes the intended curl command, then runs rm -rf /, potentially deleting critical files. The double quotes are terminated early, allowing arbitrary command injection.

Another manifestation occurs in API key validation systems that use external command-line tools. Consider a system that validates JWT tokens using OpenSSL:

// Vulnerable JWT validation using system commands
const apiKey = req.headers.authorization.replace('Bearer ', '');
const verifyCommand = `echo '${apiKey}' | openssl base64 -d | openssl dgst -sha256 -verify public.pem -signature signature.bin`;
exec(verifyCommand, (err, stdout, stderr) => {
  if (stdout.includes('Verified OK')) {
    // Proceed with authenticated request
  }
});

An attacker could craft an API key containing shell metacharacters to execute arbitrary commands on the validation server.

API keys used in database queries that execute system commands represent another attack vector. Some applications use API keys to dynamically construct database commands that include system-level operations:

// Vulnerable pattern in Python with subprocess
import subprocess

def process_api_key(api_key):
    # Malicious API key: valid_key; cat /etc/passwd; echo "
    command = f'process_data.sh {api_key}'
    subprocess.run(command, shell=True)  # shell=True is dangerous!

The shell=True parameter is particularly dangerous as it enables shell metacharacter interpretation, allowing attackers to chain multiple commands separated by semicolons, ampersands, or pipes.

Api Keys-Specific Detection

Detecting command injection vulnerabilities in API key handling requires both static code analysis and dynamic testing. For static analysis, look for patterns where API keys are passed to functions that execute system commands without proper sanitization.

Key detection patterns include:

  • API keys concatenated into command strings with shell metacharacters
  • Use of shell=True (Python) or equivalent unsafe flags
  • API keys passed to exec(), eval(), system(), or similar functions
  • Dynamic command construction using API key values
  • API keys used in eval() or similar dynamic execution contexts

Dynamic testing involves attempting to inject shell metacharacters through API keys and observing the system's response. Common injection payloads include:

validkey; echo 'injection_test';
validkey || echo 'injection_test';
validkey && echo 'injection_test';
validkey | echo 'injection_test';
validkey$(echo 'injection_test')

When testing, monitor for unexpected command execution, error messages that reveal system information, or changes in application behavior.

middleBrick's API security scanner specifically tests for command injection vulnerabilities in API endpoints. The scanner automatically attempts to inject shell metacharacters through API keys and analyzes the responses for signs of successful injection. It tests all 12 security categories including input validation and unsafe consumption patterns.

For comprehensive testing, middleBrick's black-box scanning approach sends crafted API key payloads to your endpoints and analyzes the responses for indicators of command injection, such as:

  • Unexpected output containing injected commands
  • Changes in response timing or structure
  • Error messages revealing system information
  • Unexpected side effects on the system

The scanner provides a security score (A-F) and detailed findings with severity levels, helping you prioritize remediation efforts.

Api Keys-Specific Remediation

Remediating command injection vulnerabilities in API key handling requires eliminating unsafe patterns and implementing proper input validation. The primary approach is to avoid using shell commands altogether when possible, and when unavoidable, use safe alternatives.

For Node.js applications, replace unsafe exec() calls with the spawn() or execFile() functions, which don't invoke a shell by default:

// Safe approach using execFile (no shell interpretation)
const { execFile } = require('child_process');
const apiKey = req.query.apiKey;
// Validate API key format before use
if (!/^[a-zA-Z0-9_-]{20,64}$/.test(apiKey)) {
  return res.status(400).json({ error: 'Invalid API key format' });
}
execFile('curl', ['-X', 'POST', 'https://api.example.com/data', '-H', `Authorization: Bearer ${apiKey}`], (err, stdout, stderr) => {
  console.log(stdout);
});

The key improvements here are using execFile() instead of exec() and adding strict API key validation with a regular expression that only allows expected characters.

For Python applications, use the subprocess.run() function with shell=False and pass arguments as a list:

import subprocess
import re

def process_api_key(api_key):
    # Strict validation - only alphanumeric, hyphens, and underscores
    if not re.match(r'^[a-zA-Z0-9_-]{20,64}$', api_key):
        raise ValueError('Invalid API key format')
    
    # Safe approach - no shell=True, arguments as list
    command = ['process_data.sh', api_key]
    result = subprocess.run(command, capture_output=True, text=True)
    return result.stdout

Another effective remediation is to use API client libraries instead of constructing shell commands. For HTTP requests, use dedicated HTTP clients:

// Using axios instead of shell commands
const axios = require('axios');
const apiKey = req.query.apiKey;

// Validate API key format
if (!/^[a-zA-Z0-9_-]{20,64}$/.test(apiKey)) {
  return res.status(400).json({ error: 'Invalid API key format' });
}

try {
  const response = await axios.post('https://api.example.com/data', {
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  });
  console.log(response.data);
} catch (error) {
  console.error(error);
}

This approach completely eliminates the command injection surface by using a proper HTTP client library instead of shell commands.

For applications that must use system commands, implement a strict allowlist of allowed characters and commands. Never allow shell metacharacters like ;, &&, ||, |, $(), or backticks in API keys.

middleBrick's GitHub Action can be integrated into your CI/CD pipeline to automatically scan for command injection vulnerabilities before deployment. The action can fail builds if security scores drop below your threshold, ensuring these issues are caught early.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

What's the difference between command injection and SQL injection in API key handling?
Command injection targets the operating system level, executing shell commands, while SQL injection targets database queries. Both involve untrusted input, but command injection is often more severe as it can lead to complete system compromise. In API key contexts, command injection might occur when keys are used to construct shell commands, while SQL injection would occur if keys are used in database queries without proper escaping.
How can I test my API endpoints for command injection vulnerabilities?
Use automated tools like middleBrick's API security scanner, which tests for command injection by attempting to inject shell metacharacters through API keys. Manual testing involves crafting payloads with semicolons, pipes, and other shell metacharacters, then observing system responses. Look for unexpected command execution, error messages, or changes in application behavior. Always test in a controlled environment first.