HIGH command injectionfastapiapi keys

Command Injection in Fastapi with Api Keys

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

Command Injection occurs when an attacker can control input that is passed to a shell or system-level command executed by the application. In FastAPI, this risk can be amplified when API keys are used to gate functionality but are not rigorously validated before being included in command construction. If an API key influences a subprocess call—such as being interpolated into a filename, a command argument, or a system path—an attacker who can indirectly affect the key’s usage may inject shell metacharacters to execute arbitrary commands.

Consider a scenario where an API key is read from headers and concatenated into a system command without sanitization:

import subprocess
from fastapi import FastAPI, Header, HTTPException

app = FastAPI()

@app.get("/run/{operation}")
async def run_operation(operation: str, x_api_key: str = Header(...)):
    # Dangerous: directly embedding API key and user input into a shell command
    cmd = f"echo API key {x_api_key} and executing {operation}"
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return {"output": result.stdout}

In this pattern, the API key and the operation parameter are embedded into a shell command via string interpolation. If an attacker can influence either value—perhaps by leveraging a leaked key or an insecure upstream service—they can escape the intended argument boundaries using shell metacharacters such as ;, &&, or backticks to achieve Command Injection. Even though API keys are often treated as secrets, their misuse in shell contexts can expose execution paths that lead to unauthorized command execution, data exfiltration, or system compromise.

The vulnerability is not inherent to API keys themselves, but to how they are handled when combined with dynamic command construction. For example, if logs or error messages inadvertently expose the key, or if a key is accidentally shared across services with differing trust boundaries, the attack surface grows. Furthermore, if the FastAPI application spawns subprocesses to perform administrative tasks—such as invoking external tools for data processing or integration—and incorporates API keys or derived values into those invocations without strict input validation, the risk of Command Injection increases. This pattern is especially dangerous when the subprocess runs with elevated privileges or when shell expansion is enabled (shell=True).

An attacker might probe for such weaknesses by sending crafted headers with metacharacters to observe abnormal behavior, error messages, or side effects. Because the API key is expected to be opaque, developers may overlook the need to treat it as untrusted input when it participates in command assembly. Security checks that include subprocess command construction and header-derived values—such as those performed by middleBrick—can surface these issues by correlating runtime behavior with the API specification and flagging dangerous patterns like shell injection points and unsafe consumption of headers.

Api Keys-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on preventing untrusted data from reaching shell commands, validating and restricting inputs, and avoiding shell interpretation entirely. The safest approach is to avoid shell=True and pass commands as argument lists, which disables shell metacharacter processing. Additionally, treat API keys as opaque secrets and never incorporate them into commands or logs.

Below is a secure rewrite of the earlier example using argument lists and strict validation:

import subprocess
from fastapi import FastAPI, Header, HTTPException, Depends
from pydantic import BaseModel
import shlex

app = FastAPI()

# Define allowed operations explicitly
ALLOWED_OPERATIONS = {"status", "health", "version"}

class CommandRequest(BaseModel):
    operation: str

def validate_operation(operation: str):
    if operation not in ALLOWED_OPERATIONS:
        raise HTTPException(status_code=400, detail="Operation not allowed")

@app.post("/run")
async def run_operation(body: CommandRequest, x_api_key: str = Header(...)):
    # Validate operation strictly
    validate_operation(body.operation)
    # Do NOT use the API key in the command; treat it as a secret for auth only
    # Use a list to avoid shell injection
    cmd = ["echo", "executing", body.operation]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return {"output": result.stdout}

Key practices for API key handling in FastAPI:

  • Never concatenate API keys or user-controlled values into shell commands.
  • Use subprocess with a list of arguments and shell=False (the default) to prevent metacharacter interpretation.
  • Validate all user-supplied inputs against an allowlist, especially when they map to system operations.
  • Keep API keys out of logs, error messages, and process arguments to avoid accidental exposure.
  • Leverage FastAPI dependencies for key validation and scope enforcement, and integrate with secret management solutions rather than passing keys to external processes.

Tools like middleBrick can support secure development by scanning for risky patterns such as shell injection points and unsafe consumption of headers, providing prioritized findings and remediation guidance aligned with frameworks like OWASP API Top 10.

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 using API keys in subprocess commands ever be safe?
Yes, only if the API key is never used in command construction and inputs are strictly validated and passed as argument lists with shell=False; treat API keys as secrets and avoid any shell interpolation.
How can I detect command injection risks in my FastAPI API definitions?
Review subprocess usage for shell=True and string interpolation of headers or parameters; use schema validation and allowlists; leverage automated API security scans that correlate spec definitions with runtime patterns to flag unsafe command construction.