HIGH command injectionnestjsapi keys

Command Injection in Nestjs with Api Keys

Command Injection in Nestjs with Api Keys — how this specific combination creates or exposes the vulnerability

Command injection occurs when an attacker can inject and execute arbitrary system commands through an application. In NestJS applications that accept API keys and use those keys to influence system-level operations, the combination can expose dangerous injection paths if input is not strictly validated and sanitized.

API keys are often passed as HTTP headers (e.g., x-api-key) and may be used to select configurations, backends, or commands. If a developer uses the key unsafely—such as interpolating it into a shell command or passing it to a subprocess without validation—an attacker who can influence the header may achieve command injection. For example, suppose a NestJS service receives an API key and uses it to dynamically select a script or tool to run on the server. If the key is concatenated into a command string, characters like semicolons, ampersands, or backticks can allow an attacker to append additional commands.

Consider a scenario where an endpoint uses the API key to determine which external utility to invoke. If the code builds a command string such as tool --id {apiKey} and passes it to a shell executor without sanitization, an API key like abc; rm -rf / could lead to unintended destructive behavior. Even when the key is expected to be alphanumeric, attackers may try encoded or obfuscated payloads to bypass naive checks. Because API keys are often treated as trusted identifiers, developers may skip input validation, inadvertently creating a command injection vector.

Another angle involves environment-specific behaviors. If the API key influences runtime options (e.g., selecting a region or endpoint), and those options are used to construct shell commands, the risk increases. Attackers may probe for debug modes or verbose output flags that reveal system details. Because the vulnerability arises from how the application uses the API key rather than the key itself, the risk persists even if keys are rotated or rate-limited.

NestJS does not inherently protect against command injection; it is a framework for building Node.js applications. Developers must ensure that any user-influenced data—including API key values—is treated as untrusted. Using built-in validation pipes helps enforce format constraints, but additional safeguards are required when invoking system-level operations. Security checks should reject or escape characters commonly used in command injection, such as &, |, ;, `, and $().

Finally, because this is a black-box scan scenario, middleBrick tests the unauthenticated attack surface and can detect command injection indicators by analyzing input validation and output handling. Findings include severity levels and remediation guidance, helping teams identify risky patterns where API keys interact with system commands.

Api Keys-Specific Remediation in Nestjs — concrete code fixes

Remediation focuses on strict validation, avoiding shell invocation, and using safe execution patterns. Never directly interpolate API key values into shell commands. Instead, use structured, language-native operations and strict schema validation.

First, enforce a strict format for API keys using NestJS validation pipes. For example, allow only alphanumeric characters and reject anything else:

import { ApiKeyValidationPipe } from './api-key-validation.pipe';

// In your controller
@Get('run')
runCommand(@Header('x-api-key', new ApiKeyValidationPipe()) apiKey: string) {
  // Use the key safely without shell interpolation
  return this.service.executeByKey(apiKey);
}

Create a custom pipe that validates the key format:

@Injectable()
export class ApiKeyValidationPipe implements PipeTransform {
  transform(value: string): string {
    if (!/^[a-zA-Z0-9_-]{16,64}$/.test(value)) {
      throw new BadRequestException('Invalid API key format');
    }
    return value;
  }
}

Second, avoid spawning shells entirely. Use Node.js child process methods that do not invoke a shell by default, or pass arguments as arrays. For instance, prefer execFile over exec:

import { execFile } from 'child_process';
import { promisify } from 'util';
const execFileAsync = promisify(execFile);

export class SafeExecutor {
  async executeByKey(apiKey: string): Promise {
    // Map the key to a safe internal command; do not embed the key in the command line.
    const command = this.mapKeyToCommand(apiKey);
    const { stdout } = await execFileAsync(command, [], { timeout: 5000 });
    return stdout;
  }

  private mapKeyToCommand(apiKey: string): string {
    // Use a whitelist mapping instead of dynamic construction.
    const allowed = {
      keyA: '/usr/bin/utility_a',
      keyB: '/usr/bin/utility_b',
    };
    const normalized = apiKey.replace(/[^a-zA-Z0-9_-]/g, '').substring(0, 10);
    return allowed[normalized as keyof typeof allowed] || '/usr/bin/default';
  }
}

Third, if you must construct dynamic commands, use parameterized approaches and escape all user input. However, this is less safe than the mapping approach:

import { escape } from 'querystring'; // Not for shell; use library-specific escaping if available.

// Example of safer dynamic construction (still prefer whitelisting).
const baseCmd = '/usr/bin/utility';
// Escape is illustrative; prefer execFile and avoid shell.
const safeKey = apiKey.replace(/[^a-zA-Z0-9_-]/g, '');
const finalCmd = `${baseCmd} --id ${safeKey}`;
// Only if shell is unavoidable:
const { execSync } = require('child_process');
execSync(`${baseCmd} --id ${safeKey}`, { stdio: 'pipe' });

Finally, integrate these patterns into your NestJS application structure. Use guards and interceptors to ensure validation runs early, and log suspicious input for monitoring. middleBrick can be added to your CI/CD pipeline using the GitHub Action to automatically check for insecure patterns in your codebase and fail builds if risky constructs are detected.

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

Can API keys alone cause command injection, or does it depend on how they are used?
API keys themselves do not cause command injection; the risk arises when keys are unsafely used in shell commands. Injection depends on concatenation into shell strings, lack of validation, and use of shell interpreters.
Does using environment variables for API keys prevent command injection?
Using environment variables helps separate secrets from code, but does not prevent command injection if the key is later interpolated into shell commands. Validation and safe execution patterns remain essential.