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.