From c94156e19ce979d1f7227387c6857e2be4d71bb1 Mon Sep 17 00:00:00 2001 From: tomaioo Date: Sun, 19 Jul 2026 06:23:33 -0700 Subject: [PATCH] fix(security): potential command injection via untrusted url in b The `OpenURL` function in `internal/browser/open.go` passes a caller-supplied URL directly to `exec.Command` without sanitization. On Linux and FreeBSD, this URL is passed as an argument to `xdg-open`. If a malicious application or script can control this URL, it might be possible to inject arbitrary command-line arguments (argument injection) depending on how `xdg-open` parses them, potentially leading to command execution. Signed-off-by: tomaioo <203048277+tomaioo@users.noreply.github.com> --- internal/browser/open.go | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/internal/browser/open.go b/internal/browser/open.go index 54c1adac6..690a15941 100644 --- a/internal/browser/open.go +++ b/internal/browser/open.go @@ -5,15 +5,20 @@ package browser import ( "fmt" + "net/url" "os/exec" "runtime" + "strings" ) // OpenURL launches url in the default browser. It returns once the launcher // process has started (it does not wait for the browser to close). A failure to // start the launcher is returned so callers can fall back to printing the URL. -func OpenURL(url string) error { - name, args := openCommand(runtime.GOOS, url) +func OpenURL(rawURL string) error { + if err := validateURL(rawURL); err != nil { + return err + } + name, args := openCommand(runtime.GOOS, rawURL) cmd := exec.Command(name, args...) if err := cmd.Start(); err != nil { return fmt.Errorf("browser: open url: %w", err) @@ -24,6 +29,22 @@ func OpenURL(url string) error { return nil } +// validateURL rejects URLs that could enable argument injection or that use +// unsafe schemes. Only http and https are permitted. +func validateURL(rawURL string) error { + if strings.HasPrefix(rawURL, "-") { + return fmt.Errorf("browser: open url: invalid URL") + } + parsed, err := url.Parse(rawURL) + if err != nil { + return fmt.Errorf("browser: open url: %w", err) + } + if parsed.Scheme != "http" && parsed.Scheme != "https" { + return fmt.Errorf("browser: open url: unsupported scheme %q", parsed.Scheme) + } + return nil +} + // openCommand returns the launcher command + args for a platform. Split out as a // pure function so the per-OS choice is unit-testable without spawning anything. func openCommand(goos, url string) (string, []string) {