rastray 0.15.0

Blazing-fast static analysis CLI for security, dependency, and performance audits.
# RSTR-INJ-012 — Java Runtime.exec / ProcessBuilder with concat

## Summary

A Java program calls `Runtime.getRuntime().exec(...)` or constructs a
`new ProcessBuilder(...)` from a single concatenated string —
`"command " + variable`. The single-string form goes through the
shell, so any shell metacharacter (`;`, `|`, `&`, backtick, `$()`)
inside the variable becomes a separator and runs whatever follows
with the program's privileges.

The fix is mechanical: instead of building a single shell command,
pass each argument as a separate slot in a `String[]` array (or as
varargs to `ProcessBuilder`). The OS receives `argv[0]` as the
program and `argv[1..]` as opaque strings; no shell ever parses
them.

## Severity

`Critical`.

## Languages

Java, Kotlin (`.java`, `.kt`, `.kts`).

## What rastray flags

```java
String host = request.getParameter("host");
Runtime.getRuntime().exec("ping " + host);                          // ← flagged
new ProcessBuilder("git log " + branch);                            // ← flagged
```

## What rastray deliberately does *not* flag

Argv-array and varargs forms — the recommended remediation:

```java
Runtime.getRuntime().exec(new String[] {"ping", "-c", "4", host});
new ProcessBuilder("git", "log", branch);
```

Constant-string commands:

```java
Runtime.getRuntime().exec("uptime");
```

## How to fix it

Replace the single concatenated string with an argv array. The first
slot is the executable, every other slot is one argument:

```java
ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", host);
Process proc = pb.start();
```

Even if `host` contains `;rm -rf /`, the kernel passes that whole
string as one argument to `ping`; `ping` rejects it as a malformed
hostname; nothing executes.

If you genuinely need a shell (e.g. globbing), allow-list the input
first:

```java
private static final Pattern SAFE_BRANCH = Pattern.compile("[a-zA-Z0-9_/.-]+");
if (!SAFE_BRANCH.matcher(branch).matches()) {
    throw new IllegalArgumentException("invalid branch name");
}
```

## How to suppress

If a call is provably safe (constant + sanitized input that's been
audited), suppress per-line:

```java
// rastray-ignore: RSTR-INJ-012 — branch is a tag name validated by SAFE_BRANCH above
Runtime.getRuntime().exec("git fetch " + branch);
```

## References

- [OWASP Command Injection]https://owasp.org/www-community/attacks/Command_Injection
- [SEI CERT Java IDS07-J]https://wiki.sei.cmu.edu/confluence/display/java/IDS07-J.+Sanitize+untrusted+data+passed+to+the+Runtime.exec(+method)
- [CWE-78]https://cwe.mitre.org/data/definitions/78.html
- [CWE-88 — Argument Injection]https://cwe.mitre.org/data/definitions/88.html