harden: detected non-static command inside command in run.go (#1109)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
This commit is contained in:
Anupam Mediratta
2026-09-08 07:15:33 +05:30
committed by GitHub
parent cfd36bbc74
commit 8caa6d0d38
3 changed files with 45 additions and 1 deletions
+3
View File
@@ -0,0 +1,3 @@
Require an absolute path for automatically discovered MCP Python interpreters,
including when Go's built-in relative-path protection is explicitly disabled.
Explicit interpreter overrides retain their existing behavior.
+3 -1
View File
@@ -121,7 +121,9 @@ func resolvePython(override string) (string, error) {
return override, nil
}
path, err := exec.LookPath(DefaultPythonBinary)
if err == nil {
// Go normally rejects relative results with ErrDot. Keep this invariant
// even when that protection is disabled with GODEBUG=execerrdot=0.
if err == nil && filepath.IsAbs(path) {
return path, nil
}
return "", fmt.Errorf(
+39
View File
@@ -238,6 +238,45 @@ func TestRunMissingPython(t *testing.T) {
}
}
func TestResolvePythonRejectsRelativePATH(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("POSIX executable fixture")
}
t.Chdir(t.TempDir())
if err := os.WriteFile(DefaultPythonBinary, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil {
t.Fatal(err)
}
t.Setenv("PATH", ".")
// Exercise our own guard even when Go's ErrDot protection is disabled.
t.Setenv("GODEBUG", "execerrdot=0")
if path, err := resolvePython(""); err == nil || path != "" {
t.Fatalf("resolvePython accepted relative executable: path=%q err=%v", path, err)
}
}
func TestResolvePythonAcceptsAbsolutePATH(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("POSIX executable fixture")
}
dir := t.TempDir()
want := filepath.Join(dir, DefaultPythonBinary)
if err := os.WriteFile(want, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil {
t.Fatal(err)
}
t.Setenv("PATH", dir)
if path, err := resolvePython(""); err != nil || path != want {
t.Fatalf("resolvePython = %q, %v; want %q", path, err, want)
}
}
func TestResolvePythonPreservesExplicitOverride(t *testing.T) {
t.Setenv("PATH", "")
want := filepath.Join("explicit", "python")
if path, err := resolvePython(want); err != nil || path != want {
t.Fatalf("resolvePython = %q, %v; want trusted override %q", path, err, want)
}
}
func TestRunMissingScript(t *testing.T) {
stub := makeStubPython(t)
// CacheDir exists but contains no last30days.py.