github.com/cli/safeexec@v1.0.1/README.md (about)

     1  # safeexec
     2  
     3  A Go module that provides a stabler alternative to `exec.LookPath()` that:
     4  - Avoids a Windows security risk of executing commands found in the current directory; and
     5  - Allows executing commands found in PATH, even if they come from relative PATH entries.
     6  
     7  This is an alternative to [`golang.org/x/sys/execabs`](https://pkg.go.dev/golang.org/x/sys/execabs).
     8  
     9  ## Usage
    10  ```go
    11  import (
    12      "os/exec"
    13      "github.com/cli/safeexec"
    14  )
    15  
    16  func gitStatus() error {
    17      gitBin, err := safeexec.LookPath("git")
    18      if err != nil {
    19          return err
    20      }
    21      cmd := exec.Command(gitBin, "status")
    22      return cmd.Run()
    23  }
    24  ```
    25  
    26  ## Background
    27  ### Windows security vulnerability with Go <= 1.18
    28  Go 1.18 (and older) standard library has a security vulnerability when executing programs:
    29  ```go
    30  import "os/exec"
    31  
    32  func gitStatus() error {
    33      // On Windows, this will result in `.\git.exe` or `.\git.bat` being executed
    34      // if either were found in the current working directory.
    35      cmd := exec.Command("git", "status")
    36      return cmd.Run()
    37  }
    38  ```
    39  
    40  For historic reasons, Go used to implicitly [include the current directory](https://github.com/golang/go/issues/38736) in the PATH resolution on Windows. The `safeexec` package avoids searching the current directory on Windows.
    41  
    42  ### Relative PATH entries with Go 1.19+
    43  
    44  Go 1.19 (and newer) standard library [throws an error](https://github.com/golang/go/issues/43724) if `exec.LookPath("git")` resolved to an executable relative to the current directory. This can happen on other platforms if the PATH environment variable contains relative entries, e.g. `PATH=./bin:$PATH`. The `safeexec` package allows respecting relative PATH entries as it assumes that the responsibility for keeping PATH safe lies outside of the Go program.
    45  
    46  ## TODO
    47  
    48  Ideally, this module would also provide `exec.Command()` and `exec.CommandContext()` equivalents that delegate to the patched version of `LookPath`. However, this doesn't seem possible since `LookPath` may return an error, while `exec.Command/CommandContext()` themselves do not return an error. In the standard library, the resulting `exec.Cmd` struct stores the LookPath error in a private field, but that functionality isn't available to us.