# Command injection via file upload filename when processed by system shell

- **ID:** `security/command-injection-via-file-upload-filename`
- **Domain:** security
- **Category:** runtime_error
- **Verification:** ai_generated
- **Fix Rate:** 91%

## Root Cause

The application passes the uploaded file's filename directly to a system shell command (e.g., via exec, system, or subprocess) without sanitization, allowing an attacker to inject arbitrary commands using shell metacharacters like ;, |, or `.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| PHP 8.3.0 | active | — | — |
| Node.js 20.11.0 | active | — | — |
| Python 3.12.0 | active | — | — |
| Apache Commons IO 2.15.0 | active | — | — |

## Workarounds

1. **Avoid using system shell commands with user input altogether. Use language-native APIs for file operations. For example, in Node.js, use `fs.rename(uploadedFile.path, '/target/' + sanitizedFilename)` instead of `exec('mv ' + filename + ' /target/')`. Sanitize the filename by removing all non-alphanumeric characters except dots and hyphens: `filename.replace(/[^a-zA-Z0-9._-]/g, '')`.** (95% success)
   ```
   Avoid using system shell commands with user input altogether. Use language-native APIs for file operations. For example, in Node.js, use `fs.rename(uploadedFile.path, '/target/' + sanitizedFilename)` instead of `exec('mv ' + filename + ' /target/')`. Sanitize the filename by removing all non-alphanumeric characters except dots and hyphens: `filename.replace(/[^a-zA-Z0-9._-]/g, '')`.
   ```
2. **If a shell command is unavoidable, use a whitelist of allowed characters for the filename and reject any input that does not match. For example, in Python: `import re; if not re.match(r'^[a-zA-Z0-9._-]+$', filename): raise ValueError('Invalid filename')`. Then use `subprocess.run(['mv', filename, '/target/'], shell=False)` to avoid shell interpretation.** (90% success)
   ```
   If a shell command is unavoidable, use a whitelist of allowed characters for the filename and reject any input that does not match. For example, in Python: `import re; if not re.match(r'^[a-zA-Z0-9._-]+$', filename): raise ValueError('Invalid filename')`. Then use `subprocess.run(['mv', filename, '/target/'], shell=False)` to avoid shell interpretation.
   ```
3. **Use a dedicated library for safe command execution, such as Apache Commons Exec in Java, which provides `CommandLine` and `Executor` classes that avoid shell injection. Example: `CommandLine cmdLine = new CommandLine("mv"); cmdLine.addArgument(filename); cmdLine.addArgument("/target/"); DefaultExecutor executor = new DefaultExecutor(); executor.execute(cmdLine);`.** (88% success)
   ```
   Use a dedicated library for safe command execution, such as Apache Commons Exec in Java, which provides `CommandLine` and `Executor` classes that avoid shell injection. Example: `CommandLine cmdLine = new CommandLine("mv"); cmdLine.addArgument(filename); cmdLine.addArgument("/target/"); DefaultExecutor executor = new DefaultExecutor(); executor.execute(cmdLine);`.
   ```

## Dead Ends

- **Use escapeshellarg() in PHP to escape the filename** — escapeshellarg() escapes the argument for the shell, but if the command is constructed incorrectly (e.g., using double quotes), it may still be vulnerable. Also, it does not prevent injection if the filename is used in a context like `mv $filename /target/` without quotes. (30% fail)
- **Remove only semicolons and pipes from the filename** — Attackers can use other metacharacters like backticks, $(), or newlines to execute commands. Partial sanitization is insufficient. (50% fail)
- **Use a blacklist to block common command injection patterns** — Blacklists are easily bypassed with encoding, obfuscation, or using less common shell features. A whitelist is more secure. (60% fail)
