From e41d7ac008d91dfee1be3d743cfece38c1c1a942 Mon Sep 17 00:00:00 2001 From: maxsoch Date: Mon, 6 Jul 2026 21:34:28 +0200 Subject: [PATCH] fix: exec brew directly instead of interpreting a shell string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit runBrew built a command string and ran it through zsh -c, so the shell interpreted the whole line — any metacharacter in an interpolated package name (;, $(), backticks) would have been executed. Names come from brew itself so exploitation was unlikely, but the injection class is now gone: Process gets an argument array via /usr/bin/env, which resolves brew on PATH (covering the bare "brew" fallback) and execs it with no shell in between. Also slightly faster per invocation. Co-Authored-By: Claude Fable 5 --- BrewBar/BrewBarApp.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/BrewBar/BrewBarApp.swift b/BrewBar/BrewBarApp.swift index 9db5507..9ced921 100644 --- a/BrewBar/BrewBarApp.swift +++ b/BrewBar/BrewBarApp.swift @@ -194,13 +194,15 @@ class AppDelegate: NSObject, NSApplicationDelegate { DispatchQueue.global().async { let brew = self.resolveBrewPath() let cleaned = command.replacingOccurrences(of: "brew ", with: "") - let fullCommand = "\(brew) \(cleaned)" + let arguments = [brew] + cleaned.split(separator: " ").map(String.init) - self.log("→ \(fullCommand)\n") + self.log("→ \(arguments.joined(separator: " "))\n") + // env resolves brew via PATH (covers the bare "brew" fallback) and + // execs it directly — no shell, so no metacharacter interpretation let process = Process() - process.executableURL = URL(fileURLWithPath: "/bin/zsh") - process.arguments = ["-c", fullCommand] + process.executableURL = URL(fileURLWithPath: "/usr/bin/env") + process.arguments = arguments var environment = ProcessInfo.processInfo.environment environment["SUDO_ASKPASS"] = Self.askpassURL.path