go.lang.security.audit.dangerous-syscall-exec.dangerous-syscall-exec

profile photo of semgrepsemgrep
Author
6,586
Download Count*

Detected non-static command inside Exec. Audit the input to 'syscall.Exec'. If unverified user data can reach this call site, this is a code injection vulnerability. A malicious actor can inject a malicious script to execute arbitrary code.

Run Locally

Run in CI

Defintion

rules:
  - id: dangerous-syscall-exec
    patterns:
      - pattern-either:
          - patterns:
              - pattern: |
                  syscall.$METHOD($BIN,...)
              - pattern-not: |
                  syscall.$METHOD("...",...)
              - pattern-not-inside: |
                  $BIN,$ERR := exec.LookPath("...");
                  ...
              - pattern-not-inside: |
                  $BIN = "...";
                  ...
          - patterns:
              - pattern: |
                  syscall.$METHOD($BIN,$ARGS,...)
              - pattern-not: |
                  syscall.$METHOD($BIN,[]string{"...",...},...)
              - pattern-not-inside: |
                  $ARGS := []string{"...",...};
                  ...
              - pattern-not-inside: |
                  $CMD = "...";
                  ...
                  $ARGS = []string{$CMD,...};
                  ...
              - pattern-not-inside: |
                  $CMD,$ERR := exec.LookPath("...");
                  ...
                  $ARGS = []string{$CMD,...};
                  ...
          - patterns:
              - pattern: >
                  syscall.$METHOD($BIN,[]string{"=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$EXE,...},...)
              - pattern-not: |
                  syscall.$METHOD($BIN,[]string{"...","...","...",...},...)
          - patterns:
              - pattern: |
                  syscall.$METHOD($BIN,$ARGS,...)
              - pattern-either:
                  - pattern-inside: >
                      $ARGS :=
                      []string{"=~/(sh|bash|ksh|csh|tcsh|zsh)/","-c",$EXE,...};

                      ...
                  - pattern-inside: |
                      $CMD = "=~/(sh|bash|ksh|csh|tcsh|zsh)/";
                      ...
                      $ARGS = []string{$CMD,"-c",$EXE,...};
                      ...
                  - pattern-inside: >
                      $CMD,$ERR :=
                      exec.LookPath("=~/(sh|bash|ksh|csh|tcsh|zsh)/");

                      ...

                      $ARGS = []string{$CMD,"-c",$EXE,...};

                      ...
              - pattern-not-inside: |
                  $ARGS := []string{"...","...","...",...};
                  ...
              - pattern-not-inside: |
                  $CMD = "...";
                  ...
                  $ARGS = []string{$CMD,"...","...",...};
                  ...
              - pattern-not-inside: |
                  $CMD,$ERR := exec.LookPath("...");
                  ...
                  $ARGS = []string{$CMD,"...","...",...};
                  ...
      - pattern-inside: |
          import "syscall"
          ...
      - metavariable-regex:
          metavariable: $METHOD
          regex: (Exec|ForkExec)
    message: Detected non-static command inside Exec. Audit the input to
      'syscall.Exec'. If unverified user data can reach this call site, this is
      a code injection vulnerability. A malicious actor can inject a malicious
      script to execute arbitrary code.
    metadata:
      cwe:
        - "CWE-94: Improper Control of Generation of Code ('Code Injection')"
      owasp:
        - A03:2021 - Injection
      category: security
      technology:
        - go
      confidence: LOW
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      cwe2022-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    severity: ERROR
    languages:
      - go

Examples

dangerous-syscall-exec.go

package main

import "syscall"
import "os"
import "os/exec"

func test1(userInput string) {

    binary, lookErr := exec.LookPath(userInput)
    if lookErr != nil {
        panic(lookErr)
    }

    args := []string{"ls", "-a", "-l", "-h"}

    env := os.Environ()

    // ruleid:dangerous-syscall-exec
    execErr := syscall.Exec(binary, args, env)
    if execErr != nil {
        panic(execErr)
    }
}


func test2(userInput string) {

    binary, lookErr := exec.LookPath("sh")
    if lookErr != nil {
        panic(lookErr)
    }

    args := []string{userInput, "-a", "-l", "-h"}

    env := os.Environ()

    // ruleid:dangerous-syscall-exec
    execErr := syscall.Exec(binary, args, env)
    if execErr != nil {
        panic(execErr)
    }
}

func test3(userInput string) {

    binary, lookErr := exec.LookPath("sh")
    if lookErr != nil {
        panic(lookErr)
    }

    args := []string{binary, "-c", userInput}

    env := os.Environ()

    // ruleid:dangerous-syscall-exec
    execErr := syscall.Exec(binary, args, env)
    if execErr != nil {
        panic(execErr)
    }
}



func okTest1(userInput string) {

    binary, lookErr := exec.LookPath("ls")
    if lookErr != nil {
        panic(lookErr)
    }

    args := []string{"ls", "-a", "-l", "-h"}

    env := os.Environ()

    // ok:dangerous-syscall-exec
    execErr := syscall.Exec(binary, args, env)
    if execErr != nil {
        panic(execErr)
    }
}