Skip to content

Commit 99a29a5

Browse files
fix: harden Windows path fallbacks for clip.exe and VS Code probing
Two security comments from Copilot review: - clipExePath returned bare 'clip.exe' when SystemRoot was unset, which re-introduces the PATH/cwd search the comment said we were avoiding. Chain SystemRoot -> WINDIR -> SystemDrive\Windows before defaulting to an absolute C:\Windows\System32\clip.exe. - vscodeWindowsBuildInfo built tier-3 install paths by joining USERPROFILE/ProgramFiles unconditionally; when either env var was empty, filepath.Join produced a relative path (e.g. AppData\...\Code.exe) that could match a binary in the working directory. Skip tier-3 entries whose base env var is empty.
1 parent aceaabb commit 99a29a5

2 files changed

Lines changed: 39 additions & 17 deletions

File tree

internal/pal/clipboard_windows.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,17 @@ func copyToClipboard(text string) error {
2020

2121
// clipExePath resolves clip.exe under %SystemRoot%\System32 so we never pick
2222
// up an attacker-planted clip.exe from PATH or the working directory while
23-
// copying the SQL password to the clipboard.
23+
// copying the SQL password to the clipboard. Falls back through other
24+
// well-known env vars before defaulting to the canonical C:\Windows path so
25+
// we never return a bare "clip.exe" that PATH could resolve.
2426
func clipExePath() string {
25-
if root := os.Getenv("SystemRoot"); root != "" {
26-
return filepath.Join(root, "System32", "clip.exe")
27+
for _, name := range []string{"SystemRoot", "WINDIR"} {
28+
if v := os.Getenv(name); v != "" {
29+
return filepath.Join(v, "System32", "clip.exe")
30+
}
2731
}
28-
return "clip.exe"
32+
if drive := os.Getenv("SystemDrive"); drive != "" {
33+
return filepath.Join(drive+`\`, "Windows", "System32", "clip.exe")
34+
}
35+
return `C:\Windows\System32\clip.exe`
2936
}

internal/tools/tool/vscode_windows.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,16 @@ func vscodeWindowsLocations(build string) []string {
5353
locations = append(locations, filepath.Join(install, exeName))
5454
}
5555

56-
// Tier 3: standard default install directories.
57-
locations = append(locations,
58-
filepath.Join(userDir, exeName),
59-
filepath.Join(systemDir, exeName),
60-
)
56+
// Tier 3: standard default install directories. Skip any whose base env
57+
// var was empty -- filepath.Join with an empty base yields a relative
58+
// path (e.g. AppData\...\Code.exe) that could match an unintended binary
59+
// in the working directory.
60+
if userDir != "" {
61+
locations = append(locations, filepath.Join(userDir, exeName))
62+
}
63+
if systemDir != "" {
64+
locations = append(locations, filepath.Join(systemDir, exeName))
65+
}
6166

6267
return locations
6368
}
@@ -67,15 +72,25 @@ func vscodeWindowsBuildInfo(build string) (cliName, exeName, userDir, systemDir
6772
programFiles := os.Getenv("ProgramFiles")
6873

6974
if build == "insiders" {
70-
return "code-insiders",
71-
"Code - Insiders.exe",
72-
filepath.Join(userProfile, "AppData", "Local", "Programs", "Microsoft VS Code Insiders"),
73-
filepath.Join(programFiles, "Microsoft VS Code Insiders")
75+
cliName = "code-insiders"
76+
exeName = "Code - Insiders.exe"
77+
if userProfile != "" {
78+
userDir = filepath.Join(userProfile, "AppData", "Local", "Programs", "Microsoft VS Code Insiders")
79+
}
80+
if programFiles != "" {
81+
systemDir = filepath.Join(programFiles, "Microsoft VS Code Insiders")
82+
}
83+
return
84+
}
85+
cliName = "code"
86+
exeName = "Code.exe"
87+
if userProfile != "" {
88+
userDir = filepath.Join(userProfile, "AppData", "Local", "Programs", "Microsoft VS Code")
89+
}
90+
if programFiles != "" {
91+
systemDir = filepath.Join(programFiles, "Microsoft VS Code")
7492
}
75-
return "code",
76-
"Code.exe",
77-
filepath.Join(userProfile, "AppData", "Local", "Programs", "Microsoft VS Code"),
78-
filepath.Join(programFiles, "Microsoft VS Code")
93+
return
7994
}
8095

8196
// vscodeRegistryInstallLocation reads InstallLocation from the Inno Setup

0 commit comments

Comments
 (0)