> ## Documentation Index
> Fetch the complete documentation index at: https://docs.semgrep.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Prevent Command Injection for Go

This is a command injection prevention cheat sheet by Semgrep, Inc. It contains code patterns of potential ways to run an OS command in an application. Instead of scrutinizing code for exploitable vulnerabilities, the recommendations in this cheat sheet pave a safe road for developers that mitigate the possibility of command injection in your code. By following these recommendations, you can be reasonably sure your code is free of command injection.

Learn more about [Command Injection](/learn/vulnerabilities/command-injection) vulnerability concepts.

### Check your project using Semgrep

```bash theme={null}
semgrep --config auto .
```

## 1. Running an OS command

### 1.A. Running OS commands with exec.Command()

The `Command` and `CommandContext` execute commands provided as arguments. If unverified user data can reach its call site, this may end up in a command injection vulnerability. Both `Command` and `CommandContext` have built-in protections that do not let command arguments cause trouble. But ensure that the command itself is not controlled by the user, also do not use `sh`, because internal protection does not work in this case.

Example:

```go expandable theme={null}
package main

import "os/exec"

func main() {
  // Command example
  cmd := exec.Command("echo", "hello")

  // CommandContext example
  err := exec.CommandContext(ctx, "sleep", "5").Run()

  // Not vulnerable
  cmd := exec.Command("echo", "1; cat /etc/passwd")

  // Vulnerable
  userInput :=  "echo 1 | cat /etc/passwd" // value supplied by user input
  out, _ = exec.Command("sh", "-c", userInput).Output()

  // Vulnerable
  userInput1 := "cat" // value supplied by user input
  userInput2 := "/etc/passwd" // value supplied by user input
  out, _ = exec.Command(userInput1, userInput2)
}
```

#### References

* [`Command` documentation](https://golang.org/pkg/os/exec/#Command)
* [`CommandContext` documentation](https://golang.org/pkg/os/exec/#CommandContext)

#### Mitigation

Do not let the user input in `exec.Command` and `exec.CommandContext` functions. Alternatively:

* Always try to use internal Go API (if it exists) instead of running an OS command. In other words, use internal language features instead of invoking commands that can be exploited.
* Do not include command arguments in a command string, use parameterization instead. For example:<br />
  Use:
  ```go theme={null}
  exec.Command("/path/to/myCommand", "myArg1", inputValue)
  ```
  Instead of:
  ```go theme={null}
  exec.Command("bash", "-c", "myCommand myArg1 " + inputValue)
  ```
* If it is not possible, then strip everything except alphanumeric characters from an input provided for the command string and arguments.
* Try to avoid non-literal values for the command string.
* If it is not possible, then do not let running arbitrary commands, use an allowlist for inputs.

#### Semgrep rule

[`go.lang.security.audit.dangerous-exec-command.dangerous-exec-command`](https://semgrep.dev/r/go.lang.security.audit.dangerous-exec-command.dangerous-exec-command)

### 1.B. Creating exec.Cmd struct

The `Cmd` represents an external command that is prepared or run. If unverified user data reaches its call site it can result in a command injection vulnerability. Make sure that the command path and first argument are not controlled by the user, also do not use `sh`, because internal protection does not work in such a case.

Example:

```go expandable theme={null}
package main

import (
  "os/exec"
  "os"
)

func main() {
  cmd := &exec.Cmd {
    // Path is the path of the command to run.
    Path: "/bin/echo",
    // Args holds command line arguments, including the command itself as Args[0].
    Args: []string{ "echo", "hello world" },
    Stdout: os.Stdout,
    Stderr: os.Stdout,
  }
  cmd.Start();
  cmd.Wait();

  // Args can be also omitted and {Path} will be used by default
  cmd := &exec.Cmd {
    Path: "/bin/echo"
  }

  // Vulnerable
  userInput := "/pwn/exploit" // value supplied by user input
  cmd := &exec.Cmd {
    Path: userInput
  }

  // Vulnerable
  userInput1 := "/bin/bash" // value supplied by user input
  userInput2 := []string{ "bash", "exploit.sh" } // value supplied by user input
  cmd := &exec.Cmd {
    Path: userInput1,
    Args: userInput2
  }

}
```

#### References

* [`Cmd` struct documentation](https://golang.org/pkg/os/exec/#Cmd)

#### Mitigation

Do not let the user input in `exec.Cmd` struct. Alternatively:

* Always try to use internal Go API (if it exists) instead of running an OS command.
* Try to avoid non-literal values for the command string.
* If it is not possible, then do not let running arbitrary commands, use an allowlist for inputs.
* Do not include command arguments in a command string, use parameterization instead. For example:<br />
  Use:
  ```go theme={null}
  cmd := &exec.Cmd {
    Path: "/path/to/myCommand",
    Args: []string{ "myCommand", "myArg1", inputValue },
  }
  ```
  Instead of:
  ```go theme={null}
  cmd := &exec.Cmd {
    Path: "/bin/bash",
    Args: []string{ "bash", "-c", "myCommand myArg1 " + inputValue },
  }
  ```
* If it is not possible - strip everything except alphanumeric characters from an input provided for the command string and arguments.

#### Semgrep rule

[`go.lang.security.audit.dangerous-exec-cmd.dangerous-exec-cmd`](https://semgrep.dev/r/go.lang.security.audit.dangerous-exec-cmd.dangerous-exec-cmd)

### 1.C. Writing to a command's StdinPipe

Command's `StdinPipe` returns a pipe that is connected to the command's standard input when it starts. A command injection vulnerability happens if unverified user data reaches `StdinPipe`. A malicious actor can inject a malicious script to execute arbitrary code.

Example:

```go theme={null}
package main

import (
  "fmt"
  "os/exec"
)

func main() {
  cmd := exec.Command("bash")
  // StdinPipe initialization
  cmdWriter, _ := cmd.StdinPipe() 
  cmd.Start()
  // Vulnerability when `password` controlled by user input
  cmdInput := fmt.Sprintf("sshpass -p %s", password)
  // Writing to StdinPipe
  cmdWriter.Write([]byte(cmdInput + "\n"))
  cmd.Wait()
}
```

#### References

* [`Cmd.StdinPipe` documentation](https://golang.org/pkg/os/exec/#Cmd.StdinPipe)

#### Mitigation

Do not let the user input in command's `StdinPipe`. Alternatively:

* Always try to use internal Go API (if it exists) instead of running an OS command.
* Do not use it to run the `bash` command and to avoid non-literal values for the command string.
* If it is not possible, then do not let running arbitrary commands, use a white list for inputs.
* Strip everything except alphanumeric characters from an input provided for the StdinPipe input.

#### Semgrep rule

[`go.lang.security.audit.dangerous-command-write.dangerous-command-write`](https://semgrep.dev/r/go.lang.security.audit.dangerous-command-write.dangerous-command-write)

### 1.D. Running OS commands with syscall.Exec()

`Exec`or `ForkExec` invokes the execve(2) system call. If unverified user data can reach its call site, this is a command injection vulnerability. Make sure that the command is not controlled by the user, also do not run `sh` with any possibility of user input involved in command arguments.

Example:

```go theme={null}
package main

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

// Exec invokes the execve(2) system call.
syscall.Exec(binary, args, env)
// ForkExec - combination of fork and exec, careful to be thread safe.
syscall.ForkExec(binary, args, env)

func vulnerableCode(userInput string) {
  //  Vulnerable: Do not let `path` be defined by user input
  path, _ := exec.LookPath(userInput)
  args := []string{"ls", "-a", "-l", "-h"}
  env := os.Environ()
  execErr := syscall.Exec(path, args, env)
}
```

#### References

* [`Exec` documentation](https://golang.org/pkg/syscall/#Exec)
* [`ForkExec` documentation](https://golang.org/pkg/syscall/#ForkExec)

#### Mitigation

Do not let the user input in `syscall.Exec` and `syscall.ForkExec` functions. Alternatively:

* Always try to use internal Go API (if it exists) instead of running an OS command.
* Try to avoid non-literal values for the command string.
* If it is not possible, then do not let running arbitrary commands, use an allowlist for inputs.
* Do not include command arguments in a command string, use parameterization instead. For example:<br />
  Use:
  ```go theme={null}
  syscall.Exec("/path/to/myCommand", []string{"myCommand", "myArg1", inputValue}, env)
  ```
  Instead of:
  ```go theme={null}
  syscall.Exec("/bin/bash", []string{"bash", "-c", "myCommand myArg1 " + inputValue}, env)
  ```
* If it is not possible - strip everything except alphanumeric characters from an input provided for the command string and arguments.

#### Semgrep rule

[`go.lang.security.audit.dangerous-syscall-exec.dangerous-syscall-exec`](https://semgrep.dev/r/go.lang.security.audit.dangerous-syscall-exec.dangerous-syscall-exec)
