Command Injection

Command injection occurs when attacker-controlled input alters operating-system command execution. In Python, avoid shell command strings: use structured subprocess arguments, validate inputs, and consider how the invoked program interprets them.

Command injection happens when an application lets attacker-controlled data influence a command that the operating system or a command interpreter executes. The attacker may cause unintended commands to run or change the arguments given to a program. Impacts can include data theft, file modification, or control of the application’s host, depending on the process’s permissions.

A common risky pattern is building a command string from user input and passing it to a shell, such as `subprocess.run(command, shell=True)`. Shell characters like `;`, `|`, and `&&` can then be interpreted as syntax rather than ordinary data. The exact syntax and behavior depend on the shell.

Prefer an API that accepts an argument list, such as `subprocess.run([program, arg1, arg2])`, and leave `shell` disabled. This prevents shell metacharacters in an argument from being interpreted by a shell, but it does not make every invocation safe: the target program may interpret a value as an option or expression, and unsafe choices of executable or arguments can still be dangerous.

Validate values against the expected format and allowed choices, use fixed executable paths where practical, and apply least privilege to the process. If a command needs complex shell behavior, avoid composing it from untrusted strings; redesign the operation or carefully construct and review the command for the specific platform and shell.

Key points

Interview questions

What is command injection, and why is it dangerous?

Command injection is a vulnerability where untrusted input changes a command or its arguments in a way that causes unintended operating-system actions. A typical cause is joining input into a shell command string. Depending on what the application can access, an attacker may read or alter data, or run other commands with the application's privileges.

How would you safely invoke an external command in a Python backend?

Avoid building a shell command string from user input. In Python, pass a sequence of arguments to `subprocess.run` and leave `shell` disabled, so a shell does not parse metacharacters within an argument. Validate input against the expected format and allowed values. Also consider whether the target program treats the value as an option or otherwise gives it special meaning.

Why is `shell=False` not a complete security guarantee?

`shell=False` prevents a shell from interpreting shell operators in an argument, but it does not guarantee that the invoked program treats that argument as harmless data. A program may recognize a leading hyphen as an option, or accept values that trigger risky behavior through its own syntax. Use fixed executables, validate arguments, and use the target program's supported mechanisms for separating options from positional values when available.

How does input validation differ from escaping?

Escaping attempts to transform data so that a particular interpreter treats it as literal input, but correct escaping depends on the interpreter and context. Validation restricts input to an accepted domain, while avoiding the shell removes a parsing layer. For subprocesses, structured arguments with `shell=False` are usually a stronger baseline than manually escaping a command string, but validation and target-specific safeguards remain important.