flawopen.com/Command Injection/Java

Command Injection in Java

Critical CWE-78 Draft — pending review
ELI5

Imagine a smart home speaker. Safe execution is pressing the preset button. Command injection is when someone shouts into the microphone 'Play music AND unlock front door', and the speaker executes both commands.

Key terms on this page
ProcessBuilder
The modern, safe Java API for process creation that takes command arguments as a List<String> without a shell.
Runtime.exec(String)
Legacy Java API that tokenizes a single string using StringTokenizer, frequently leading to argument injection or shell execution traps.

What's happening

In Java applications, command injection typically occurs when developers call Runtime.getRuntime().exec(queryString) or construct a shell call (sh -c or cmd.exe /c) with concatenated request parameters.

Real-world impact

Enterprise Java systems, including Jenkins, Apache Struts, and Spring Cloud Gateway, have suffered severe critical CVEs enabling unauthorized remote shell access across enterprise intranets.

CVE-2022-22947 & NIST National Vulnerability Database.

Vulnerable vs. fixed

VULNERABLE
// Runtime.exec with string concatenation
public class PingService {
    public void ping(String host) throws Exception {
        // Attacker input: "127.0.0.1; whoami"
        String command = "sh -c ping -c 1 " + host;
        Process process = Runtime.getRuntime().exec(command);
    }
}
FIXED
// ProcessBuilder with discrete argument list
public class PingService {
    public void ping(String host) throws Exception {
        // host is strictly isolated as an argument
        List command = List.of("ping", "-c", "1", host);
        ProcessBuilder pb = new ProcessBuilder(command);
        Process process = pb.start();
    }
}

Why the fix works

ProcessBuilder passes the command and arguments as a distinct array directly to the underlying OS API (CreateProcessW on Windows or execve on Linux), bypassing shell command parsers completely.

Gotchas

StringTokenizer behavior in Runtime.exec(String)

Java tokenizes by spaces, meaning arguments containing spaces cannot be passed reliably without breaking quotes, leading developers to wrap commands in sh -c.

Common misconceptions

"Java SecurityManager protects against command execution"

SecurityManager has been deprecated for removal since Java 17. ProcessBuilder and OS containment are the true security controls.

How to check if you're affected

grep -rn "Runtime.getRuntime().exec(" --include="*.java" .
Run SpotBugs with FindSecBugs (rule COMMAND_INJECTION) in your Maven/Gradle build.

Prevention checklist

FAQ

Is ProcessBuilder safe from all command injection?

Yes from shell injection. However, you must still ensure the program being executed does not interpret user arguments as unintended option flags.

References

View in: Python JavaScript Go Java PHP C# Ruby C/C++ Rust Kotlin Swift Solidity (N/A)
Also see: SQL Injection XSS Path Traversal Insecure Deserialization