java.lang.security.audit.command-injection-process-builder.command-injection-process-builder

profile photo of semgrepsemgrep
Author
6,314
Download Count*

A formatted or concatenated string was detected as input to a ProcessBuilder call. This is dangerous if a variable is controlled by user input and could result in a command injection. Ensure your variables are not controlled by users or sufficiently sanitized.

Run Locally

Run in CI

Defintion

rules:
  - id: command-injection-process-builder
    pattern-either:
      - patterns:
          - pattern: |
              new ProcessBuilder($CMD,...)
          - pattern-not-inside: |
              $CMD = "...";
              ...
          - pattern-not-inside: |
              $CMD = Arrays.asList("...",...);
              ...
          - pattern-not-inside: |
              $CMD = new String[]{"...",...};
              ...
          - pattern-not: |
              new ProcessBuilder("...",...)
          - pattern-not: |
              new ProcessBuilder(new String[]{"...",...},...)
          - pattern-not: |
              new ProcessBuilder(Arrays.asList("...",...),...)
      - patterns:
          - pattern: |
              $PB.command($CMD,...)
          - pattern-inside: |
              $TYPE $PB = new ProcessBuilder(...);
              ...
          - pattern-not-inside: |
              $CMD = "...";
              ...
          - pattern-not-inside: |
              $CMD = Arrays.asList("...",...);
              ...
          - pattern-not-inside: |
              $CMD = new String[]{"...",...};
              ...
          - pattern-not: |
              $PB.command("...",...)
          - pattern-not: |
              $PB.command(new String[]{"...",...},...)
          - pattern-not: |
              $PB.command(Arrays.asList("...",...),...)
      - patterns:
          - pattern-either:
              - pattern: >
                  new
                  ProcessBuilder("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$ARG,...)
              - pattern: |
                  new ProcessBuilder("cmd","/c",$ARG,...)
              - pattern: |
                  new ProcessBuilder(Arrays.asList("cmd","/c",$ARG,...),...)
              - pattern: |
                  new ProcessBuilder(new String[]{"cmd","/c",$ARG,...},...)
              - patterns:
                  - pattern-either:
                      - pattern: |
                          new ProcessBuilder($CMD,"/c",$ARG,...)
                      - pattern: >
                          new
                          ProcessBuilder(Arrays.asList($CMD,"/c",$ARG,...),...)
                      - pattern: >
                          new ProcessBuilder(new
                          String[]{$CMD,"/c",$ARG,...},...)
                  - pattern-inside: |
                      $CMD = "cmd";
                      ...
          - pattern-not-inside: |
              $ARG = "...";
              ...
          - pattern-not: |
              new ProcessBuilder("...","...","...",...)
          - pattern-not: |
              new ProcessBuilder(new String[]{"...","...","...",...},...)
          - pattern-not: |
              new ProcessBuilder(Arrays.asList("...","...","...",...),...)
      - patterns:
          - pattern-either:
              - pattern: |
                  $PB.command("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$ARG,...)
              - pattern: |
                  $PB.command("cmd","/c",$ARG,...)
              - pattern: >
                  $PB.command(Arrays.asList("=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$ARG,...),...)
              - pattern: |
                  $PB.command(Arrays.asList("cmd","/c",$ARG,...),...)
              - pattern: >
                  $PB.command(new
                  String[]{"=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$ARG,...},...)
              - pattern: |
                  $PB.command(new String[]{"cmd","/c",$ARG,...},...)
              - patterns:
                  - pattern-either:
                      - pattern: |
                          $PB.command($CMD,"-c",$ARG,...)
                      - pattern: |
                          $PB.command(Arrays.asList($CMD,"-c",$ARG,...),...)
                      - pattern: |
                          $PB.command(new String[]{$CMD,"-c",$ARG,...},...)
                  - pattern-inside: |
                      $CMD = "=~/(sh|bash|ksh|csh|tcsh|zsh)/";
                      ...
              - patterns:
                  - pattern-either:
                      - pattern: |
                          $PB.command($CMD,"/c",$ARG,...)
                      - pattern: |
                          $PB.command(Arrays.asList($CMD,"/c",$ARG,...),...)
                      - pattern: |
                          $PB.command(new String[]{$CMD,"/c",$ARG,...},...)
                  - pattern-inside: |
                      $CMD = "cmd";
                      ...
          - pattern-inside: |
              $TYPE $PB = new ProcessBuilder(...);
              ...
          - pattern-not-inside: |
              $ARG = "...";
              ...
          - pattern-not: |
              $PB.command("...","...","...",...)
          - pattern-not: |
              $PB.command(new String[]{"...","...","...",...},...)
          - pattern-not: |
              $PB.command(Arrays.asList("...","...","...",...),...)
    message: A formatted or concatenated string was detected as input to a
      ProcessBuilder call. This is dangerous if a variable is controlled by user
      input and could result in a command injection. Ensure your variables are
      not controlled by users or sufficiently sanitized.
    metadata:
      cwe:
        - "CWE-78: Improper Neutralization of Special Elements used in an OS
          Command ('OS Command Injection')"
      owasp:
        - A01:2017 - Injection
        - A03:2021 - Injection
      category: security
      technology:
        - java
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Command Injection
    severity: ERROR
    languages:
      - java

Examples

command-injection-process-builder.java

public class TestExecutor {

    private Pair<Integer, String> test1(String command, Logger logAppender) throws IOException {
      String[] cmd = new String[3];
      String osName = System.getProperty("os.name");
      if (osName.startsWith("Windows")) {
          cmd[0] = "cmd.exe";
          cmd[1] = "/C";
      } else {
          cmd[0] = "/bin/bash";
          cmd[1] = "-c";
      }
      cmd[2] = command;

      // ruleid: command-injection-process-builder
      ProcessBuilder builder = new ProcessBuilder(cmd);
      builder.redirectErrorStream(true);
      Process proc = builder.start();
      return Pair.newPair(1, "Killed");
    }

    public String test2(String userInput) {
      ProcessBuilder builder = new ProcessBuilder();
      // ruleid: command-injection-process-builder
      builder.command(userInput);
      return "foo";
    }

    public String test3(String userInput) {
      ProcessBuilder builder = new ProcessBuilder();
      // ruleid: command-injection-process-builder
      builder.command("bash", "-c", userInput);
      return "foo";
    }

    public String test4(String userInput) {
      ProcessBuilder builder = new ProcessBuilder();
      // ruleid: command-injection-process-builder
      builder.command("cmd", "/c", userInput);
      return "foo";
    }

    public String okTest() {
      ProcessBuilder builder = new ProcessBuilder();
      // ok: command-injection-process-builder
      builder.command("bash", "-c", "ls");
      return "foo";
    }


}