You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
4
6
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).
8
8
9
-
funcgitStatus() 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
22
10
```go
23
11
import (
24
12
"os/exec"
@@ -35,6 +23,26 @@ func gitStatus() error {
35
23
}
36
24
```
37
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
+
funcgitStatus() 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
+
38
46
## TODO
39
47
40
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.
0 commit comments