← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Command Injection

Security CWE-78 OWASP A3:2021 CVSS 9.8 PHP 5.0+ Intermediate
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches' (d5). The term's detection_hints list semgrep, phpstan, and psalm as tools that can catch patterns like shell_exec( or exec( with variable interpolation. These are specialist SAST tools rather than default linters, and they catch the common case but may miss indirect data flows or less obvious injection points like image processing CLI calls.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix indicates using escapeshellarg() on every argument or preferring PHP-native functions. This is typically a targeted fix within one component — replacing shell_exec calls with native PHP equivalents or wrapping arguments — but may require touching multiple call sites within a file or small set of files.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Command injection vulnerabilities are typically localised to specific code paths that invoke shell commands. The fix doesn't require architectural rework — it's about securing the specific call sites. The applies_to scope (web, cli contexts) is broad, but the burden falls only on code that actually uses shell execution, not the entire codebase.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field explicitly states that developers believe escapeshellarg() makes all shell calls safe, when it only secures arguments — not the command name itself. This is a documented gotcha that most security-aware devs eventually learn, but it contradicts the intuitive assumption that 'escaping = safe'. The common_mistakes also highlight traps like injection via argument structure even after escaping.

About DEBT scoring →

Also Known As

OS command injection shell injection RCE via shell

TL;DR

User input passed to a shell function (exec, system, shell_exec) allows arbitrary OS command execution.

Explanation

Command injection occurs when user-controlled data is incorporated into a shell command without sanitisation. Attackers can append additional commands using shell metacharacters (;, |, &&) to run arbitrary programs with the web server's privileges — reading files, exfiltrating data, installing backdoors, or pivoting to other systems. Prevention: avoid shell functions entirely where possible; if unavoidable, use escapeshellarg() on every argument and escapeshellcmd() on the command.

How It's Exploited

POST filename=image.jpg; rm -rf /var/www
# Deletes your web root

Diagram

flowchart TD
    USER_CMD[User input: filename] --> CONCAT2[exec ls -la . filename .]
    CONCAT2 -->|input: . ; rm -rf /| EXEC2[Shell executes:<br/>ls -la .<br/>rm -rf /]
    EXEC2 --> DISASTER[Files deleted!]
    subgraph Fix
        ESCAPE[escapeshellarg wraps in quotes<br/>escapes all shell metacharacters]
        VALIDATE[Allowlist valid inputs<br/>reject anything else]
        AVOID[Use PHP functions directly<br/>avoid shell when possible]
    end
style CONCAT2 fill:#f85149,color:#fff
style DISASTER fill:#f85149,color:#fff
style ESCAPE fill:#238636,color:#fff

Common Misconception

escapeshellarg() makes all shell calls safe. It secures arguments but does nothing if user input appears in the command name itself. The safest approach is proc_open() with an array, which bypasses the shell entirely.

Why It Matters

Any user input reaching shell execution functions can run arbitrary OS commands with the web server's privileges — full server compromise from a single unvalidated parameter.

Common Mistakes

  • Using shell_exec(), system(), or exec() with unsanitised user input even after escapeshellarg().
  • Passing user-controlled arguments where escapeshellarg() is applied to the whole string but injection happens via argument structure.
  • Using PHP functions that invoke a shell implicitly — preg_replace with /e modifier (removed in PHP 7), or older mail() with fifth argument.
  • Not considering that command injection can occur in less obvious places like image processing CLI calls.

Code Examples

✗ Vulnerable
$file = $_POST['filename'];
exec("convert $file output.pdf");
✓ Fixed
// escapeshellarg wraps in single quotes and escapes embedded quotes
$file = escapeshellarg($_POST['filename']);
exec('convert ' . $file . ' output.pdf');

// Better: avoid shell entirely — use proc_open with an array
proc_open(['convert', $file, 'output.pdf'], $descriptors, $pipes);

Added 15 Mar 2026
Edited 22 Mar 2026
Views 63
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 5 pings F 2 pings S 1 ping S 3 pings M 2 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T 0 pings F 0 pings S 2 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 11 Perplexity 8 Amazonbot 7 Ahrefs 6 Google 5 ChatGPT 5 Unknown AI 3 Claude 2 Meta AI 1 Majestic 1 Bing 1 SEMrush 1 PetalBot 1 Sogou 1
crawler 49 crawler_json 4
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Use escapeshellarg() on every argument passed to shell_exec/exec; prefer PHP-native functions over shell commands entirely
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
shell_exec( or exec( or system( or passthru( or backtick with variable interpolation
Auto-detectable: ✓ Yes semgrep phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: High Context: Function Tests: Update
CWE-78 CWE-88


✓ schema.org compliant