-
Notifications
You must be signed in to change notification settings - Fork 497
Description
Describe the bug
The Java rule command-injection-process-builder produces a false negative and misses a common RCE pattern.
The rule correctly detects ProcessBuilder(...) constructor usage and direct command(...) calls on a ProcessBuilder variable. However, it does not account for fluent (chained) invocations where command() is called as part of a method chain starting from new ProcessBuilder().
As a result, command injection is not detected when:
ProcessBuilderis instantiated inline without being assigned to a local variablecommand()is invoked within a fluent chain- a shell is executed with login flags (
-l -c), not just-c
To Reproduce
Undetected vulnerable example:
@Service
public class BashExecutorService {
public String run(final String command) {
try {
Process process = new ProcessBuilder()
.redirectErrorStream(true)
.command("/bin/bash", "-l", "-c", command)
.start();
return "ok";
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}No finding is reported by command-injection-process-builder.
Detected example (works as expected):
public class TestExecutor {
public String test(String userInput) {
ProcessBuilder builder = new ProcessBuilder();
// ruleid: command-injection-process-builder
builder.command("bash", "-c", userInput);
return "foo";
}
}Expected behavior
The rule should flag the fluent invocation case, as it is semantically equivalent to already detected patterns.
Any invocation of a shell (bash, sh, cmd) with -c (including cases with additional flags such as -l) where the command argument is a variable should be reported, regardless of whether ProcessBuilder is stored in a local variable or used inline.
Priority
How important is this to you?
- P0: blocking me from making progress
- P1: this will block me in the near future
- P2: annoying but not blocking me
Additional Context
The root cause appears to be rule constraints that rely on:
pattern-inside: |
$TYPE $PB = new ProcessBuilder(...);
...This pattern never matches in the following real-world scenario:
new ProcessBuilder()
.redirectErrorStream(true)
.command("/bin/bash", "-l", "-c", command)
.start();Key differences from already covered cases:
command()is invoked as part of a fluent chain, not as a standalone statement.ProcessBuilderis not assigned to a local variable beforecommand()is called.- A login shell is used (
-l -c), while the rule primarily matches only-c.
Because of (1) and (2), the pattern-inside constraint never triggers, leading to a false negative. This usage pattern is common in Spring services and command execution helpers, so missing it reduces the practical effectiveness of the rule for Java RCE detection.
If useful, I can provide a minimal rule patch or test cases that demonstrate this gap.