There’s a class of security vulnerability that’s particularly insidious: binary hijacking on Windows. If a tool calls taskkill without an absolute path, an attacker can place a malicious taskkill.exe in a directory that’s searched before the system directory. The tool runs the attacker’s binary instead — with whatever privileges the tool has.
Gitlawb Zero just fixed this. Here’s why it matters, how the fix works, and what every Windows developer should know about PATH-based execution risks.
The Bug: PATH Search Order Is an Attack Surface
Zero’s process management code on Windows called taskkill without specifying the full path. On Windows, the PATH search order means the first matching binary in any PATH directory wins. The search order is:
- The directory containing the application executable
- The current working directory
- System directories (
C:\Windows\System32,C:\Windows) - Directories in the user and system PATH environment variables
If an attacker placed a malicious taskkill.exe in a directory that’s earlier in PATH than C:\Windows\System32 — say, a project’s node_modules/.bin, a user’s ~/bin, or even the current working directory — Zero would execute the attacker’s code instead of the real Windows utility.
The Fix: Absolute Path Resolution
fix(windows): resolve absolute path for taskkill to prevent hijacking (#617)
The fix resolves taskkill to its absolute path (C:\Windows\System32\taskkill.exe) before executing it. This eliminates the PATH search entirely — the correct binary is always used, regardless of what’s in PATH or the current directory.
// Before: vulnerable to PATH hijacking
cmd := exec.Command("taskkill", "/PID", pidStr, "/F")
// After: absolute path, no PATH search
taskkillPath, _ := exec.LookPath("taskkill") // resolves to C:\Windows\System32\taskkill.exe
cmd := exec.Command(taskkillPath, "/PID", pidStr, "/F")
The fix uses exec.LookPath which searches PATH but returns the absolute path to the first match. Since C:\Windows\System32 is always in the system PATH and comes before user directories, the legitimate binary wins — but crucially, the returned absolute path bypasses any subsequent PATH manipulation.
Why This Matters: Binary Hijacking Is Real
Binary hijacking is a well-known Windows vulnerability, but it’s surprisingly common in open-source tools. Most developers test on macOS or Linux, where the PATH search is less exploitable (the current directory isn’t in PATH by default, and system binaries are in protected locations). On Windows, it’s a real attack vector:
| Scenario | Risk |
|---|---|
Cloned repo with malicious taskkill.exe in repo root |
Developer runs Zero in repo → attacker code executes |
Compromised node_modules/.bin from supply chain attack |
Any tool run in project directory is affected |
User writes custom scripts to ~/bin (in PATH) |
Typosquatting or malicious scripts intercept system calls |
| Shared development machines | One user’s malicious binary affects others |
Zero’s fix is the right approach:
- Always use absolute paths for system utilities
- Don’t rely on PATH for security-critical operations
- Validate binary locations before execution
Beyond taskkill: The General Pattern
This isn’t just about taskkill. Any Windows tool that shells out to system utilities without absolute paths has the same vulnerability. Common targets:
powershell.exe,cmd.exe— command executionnet.exe,sc.exe— service managementreg.exe— registry manipulationwmic.exe— WMI queriesfindstr.exe,where.exe— search utilities- Git, npm, python, node — if not using absolute paths
The secure pattern: Resolve the absolute path once at startup (or use a known system path), cache it, and always execute the cached absolute path.
// Secure pattern for any system binary
var (
taskkillPath string
powershellPath string
)
func init() {
var err error
taskkillPath, err = exec.LookPath("taskkill")
if err != nil { log.Fatal("taskkill not found") }
powershellPath, err = exec.LookPath("powershell.exe")
if err != nil { log.Fatal("powershell not found") }
}
// Use cached absolute paths everywhere
func killProcess(pid int) error {
return exec.Command(taskkillPath, "/PID", strconv.Itoa(pid), "/F").Run()
}
What This Means for Zero Users
Zero on Windows is now more secure against a class of attacks that most users never think about — but that attackers definitely do. It’s the kind of security hardening that separates a tool you trust from a tool you hope works.
For developers building CLI tools on Windows: audit your exec.Command calls. Every unqualified system binary name is a potential hijack vector. The fix is trivial (resolve absolute path once), the risk is real, and the users who get protected will never know — which is exactly how good security should work.
Related articles
- Coding Agents in 2026: Three Hard Lessons HN Developers Learned the Expensive Way
- Your AI Agents Config Directory Is Now the Most Dangerous Place on Your Machine
- Coding Agent Security Checklist 2026 — The Operators Hardening Guide
- Beware: Gitlawb Zero v0.4.0 Closed a Hole Where a Cloned Repo Could Re-Enable the MCP Servers You Disabled
Tired of deciding which AI subscription to keep? aiFiesta bundles GPT, Claude, Gemini, Grok, DeepSeek, Perplexity and more for $12/mo — less than half of a single premium chat sub.