Skip to content

Commit 7342e94

Browse files
authored
Clarify differences vs. Go 1.19 behavior
1 parent da4a527 commit 7342e94

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

README.md

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
11
# safeexec
22

3-
A Go module that provides a safer alternative to `exec.LookPath()` on Windows.
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.
46

5-
The following, relatively common approach to running external commands has a subtle vulnerability on Windows:
6-
```go
7-
import "os/exec"
7+
This is an alternative to [`golang.org/x/sys/execabs`](https://pkg.go.dev/golang.org/x/sys/execabs).
88

9-
func gitStatus() error {
10-
// On Windows, this will result in `.\git.exe` or `.\git.bat` being executed
11-
// if either were found in the current working directory.
12-
cmd := exec.Command("git", "status")
13-
return cmd.Run()
14-
}
15-
```
16-
17-
Searching the current directory (surprising behavior) before searching folders listed in the PATH environment variable (expected behavior) seems to be intended in Go and unlikely to be changed: https://github.com/golang/go/issues/38736
18-
19-
Since Go does not provide a version of [`exec.LookPath()`](https://golang.org/pkg/os/exec/#LookPath) that only searches PATH and does not search the current working directory, this module provides a `LookPath` function that works consistently across platforms.
20-
21-
Example use:
9+
## Usage
2210
```go
2311
import (
2412
"os/exec"
@@ -35,6 +23,26 @@ func gitStatus() error {
3523
}
3624
```
3725

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+
3846
## TODO
3947

4048
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.

0 commit comments

Comments
 (0)