HIGH command injectionexpressapi keys

Command Injection in Express with Api Keys

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

Command injection in an Express API that uses API keys often arises when the server validates the key but then passes unchecked external data to a system command. Even with a valid API key confirming caller identity, the endpoint may still be unsafe if it builds shell commands using user-controlled inputs such as filenames, IP addresses, or query parameters. For example, concatenating a user-supplied filename into an exec or spawn call can allow an authenticated caller to inject additional shell commands via shell metacharacters like ;, &&, or backticks.

Consider an Express route that expects an API key in a header and a filename via query string to generate a report. If the implementation does not sanitize or escape the filename, an authenticated caller can supply a value such as report.txt; cat /etc/passwd. When the server builds a shell command, the injected segment runs with the same privileges as the process, potentially exposing sensitive data or enabling further abuse. This pattern violates secure handling of external input and is commonly flagged as an OWASP API Top 10 item related to injection.

Another scenario involves environment variables or configuration values that include user-controlled data. For instance, an API key–scoped integration might invoke a helper that runs ping or curl to validate a remote endpoint. If the target hostname or path is derived from request parameters without strict allowlisting or encoding, an authenticated user can pivot to internal services, trigger SSRF-like behavior, or cause command chaining through crafted input. Even with correct API key checks, missing input validation and unsafe subprocess construction expose the attack surface.

OpenAPI/Swagger specifications can inadvertently document permissive parameters that encourage unsafe usage. If the spec accepts a string for a parameter that is later used in a shell command without type or pattern constraints, runtime behavior may diverge from intended design. middleBrick’s OpenAPI/Swagger spec analysis resolves $ref definitions and cross-references spec definitions with runtime findings, helping to highlight mismatches where an API key–protected endpoint still accepts dangerous input patterns.

Real-world examples include CVE patterns where authenticated endpoints execute system utilities with unsanitized arguments. These findings are surfaced in middleBrick’s security checks, which test unauthenticated attack surfaces and authenticated scenarios when credentials are provided. The scanner does not fix the code but provides prioritized findings with severity levels and remediation guidance, enabling developers to tighten input validation, use allowlists, and avoid shell construction altogether.

Api Keys-Specific Remediation in Express — concrete code fixes

To remediate command injection in Express while preserving API key validation, avoid shell execution entirely. Use native, language-safe operations instead of spawning shell commands for tasks such as file manipulation, network checks, or data conversion. When shell interaction is unavoidable, strict allowlisting, argument arrays, and environment isolation are required.

Insecure example to avoid

const { exec } = require('child_process');
app.get('/report', (req, res) => {
  const apiKey = req.get('X-API-Key');
  // API key validation omitted for brevity
  const filename = req.query.file;
  exec(`cat ${filename}`, (err, stdout) => {
    if (err) return res.status(500).send('Error');
    res.send(stdout);
  });
});

In this example, a valid API key does not prevent command injection because filename is directly interpolated into the shell command. An attacker can exploit this even when authenticated.

Safe remediation using native APIs

const fs = require('fs');
app.get('/report', (req, res) => {
  const apiKey = req.get('X-API-Key');
  // Validate apiKey against a secure store or middleware
  const filename = req.query.file;
  const allowed = new Set(['report.txt', 'summary.csv', 'metrics.json']);
  if (!allowed.has(filename)) {
    return res.status(400).send('Invalid file');
  }
  fs.readFile(`/data/${filename}`, 'utf8', (err, data) => {
    if (err) return res.status(500).send('Error');
    res.type('txt').send(data);
  });
});

This approach removes the shell entirely, uses an allowlist for filenames, and prevents injection regardless of API key validity. The API key can be validated via middleware that checks against a secure key store or a database before allowing access to the handler.

When shell execution is unavoidable: use spawn with argument array

const { spawn } = require('child_process');
app.get('/ping', (req, res) => {
  const apiKey = req.get('X-API-Key');
  // Validate apiKey
  const host = req.query.host;
  const allowedHosts = new Set(['api.internal.example', 'monitor.example']);
  if (!allowedHosts.has(host)) {
    return res.status(400).send('Invalid host');
  }
  const child = spawn('ping', ['-c', '4', host]);
  let output = '';
  child.stdout.on('data', (data) => output += data);
  child.on('close', (code) => {
    if (code !== 0) return res.status(502).send('Unreachable');
    res.send(`Ping output: ${output}`);
  });
});

Here, arguments are passed as an array, which avoids shell parsing. The host is strictly allowlisted, ensuring that even with a valid API key, only preapproved targets can be probed. This pattern reduces risk while still allowing controlled external command execution.

middleBrick’s scans can validate these practices by checking whether endpoints that use API keys also exhibit unsafe subprocess construction or missing input validation. Developers should pair authentication checks with secure coding patterns to reduce the likelihood of injection across authenticated paths.

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

Does a valid API key prevent command injection?
No. API key validation confirms identity but does not sanitize external input. If user-controlled data is passed to a shell command, injection can still occur when the caller is authenticated.
What is the safest way to handle file operations in Express APIs?
Avoid shell commands entirely. Use native file system APIs with strict allowlists for filenames and paths, and enforce scope-based access controls per API key or client permissions.