OS Command Injection
Summary
Subset of the Command Injection - Generic bucket focused on direct shell-out paths. Top patterns: unauth Jenkins script-console RCE, Confluence OGNL CVE-2021-26084, CVE-2021-26085, Atlassian/Telerik RCE, and Ruby coreutils-style util-script bugs (rdoc, wait_writable) where filenames containing pipe characters trigger shell exec via Kernel.open.
Top Affected Components / Targets
Public Jenkins instancesConfluence Server / Data CenterTelerik UIRuby/PHP file-utility scripts on shared hostingWindows desktop apps with custom protocol handlers
Common Attack Vectors
Probe /script (Jenkins), /CFIDE (ColdFusion), /Telerik.Web.UI.WebResource.axd (Telerik), /pages/createpage-entervariables.action (Confluence)Submit OGNL injection to ConfluenceUpload arbitrary file via Telerik DialogHandlerAll OS-command-injection vectors from the broader Command Injection synthesis
Common Payloads
println 'ls'.execute().text (Jenkins)Confluence OGNL: \u0027+#{...}+\u0027 with new Runtime().exec(...)Telerik DialogHandler payload (CVE-2019-18935)All payloads from the broader Command Injection synthesis
Detection Strategy
Out-of-band and time-based shell-metacharacter injection, plus JNDI/Log4Shell-style probing, cover the direct exploitation path; version-fingerprint CVE matching catches the well-known, unauthenticated RCE chains in specific software (Confluence's CVE-2021-26084, Telerik's CVE-2019-18935) that account for a large share of real-world command-injection disclosures.
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
- Same as Command Injection - Generic.
- Jenkins script-console requires auth in modern setups - flag only when unauth access is confirmed.
How to Test
Manual Testing Methodology
Here is a systematic approach to identifying OS Command Injection vulnerabilities in a target application.
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.
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.
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 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.
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.
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, 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 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.