diff --git a/go.mod b/go.mod index c84d2ea419..8f872e9368 100644 --- a/go.mod +++ b/go.mod @@ -37,7 +37,7 @@ require ( github.com/kevinburke/ssh_config v1.5.0 github.com/klauspost/pgzip v1.2.6 github.com/linuxkit/virtsock v0.0.0-20241009230534-cb6a20cc0422 - github.com/mattn/go-shellwords v1.0.12 + github.com/mattn/go-shellwords v1.0.13 github.com/mattn/go-sqlite3 v1.14.39 github.com/mdlayher/vsock v1.2.1 github.com/moby/docker-image-spec v1.3.1 diff --git a/go.sum b/go.sum index b0af5bee31..de14dad12c 100644 --- a/go.sum +++ b/go.sum @@ -233,8 +233,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= -github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-shellwords v1.0.13 h1:DC0OMEpGjm6LfNFU4ckYcvbQKyp2vE8atyFGXNtDcf4= +github.com/mattn/go-shellwords v1.0.13/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.39 h1:sIwSjlJGOaRJjw44/HXaeTblZMjseqr6OOio1tz/+JI= github.com/mattn/go-sqlite3 v1.14.39/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mdlayher/packet v1.1.2 h1:3Up1NG6LZrsgDVn6X4L9Ge/iyRyxFEFD9o6Pr3Q1nQY= diff --git a/vendor/github.com/mattn/go-shellwords/shellwords.go b/vendor/github.com/mattn/go-shellwords/shellwords.go index 1b42a00170..3747e35494 100644 --- a/vendor/github.com/mattn/go-shellwords/shellwords.go +++ b/vendor/github.com/mattn/go-shellwords/shellwords.go @@ -136,6 +136,12 @@ loop: for _, r := range line { i++ if escaped { + if r == 't' { + r = '\t' + } + if r == 'n' { + r = '\n' + } buf += string(r) escaped = false got = argSingle @@ -194,23 +200,49 @@ loop: backtick = "" backQuote = !backQuote } + case ')': if !singleQuoted && !doubleQuoted && !backQuote { if p.ParseBacktick { - if dollarQuote { - out, err := shellRun(backtick, p.Dir) - if err != nil { - return nil, err - } - buf = buf[:len(buf)-len(backtick)-2] + out + // Security fix: + // A bare ')' must never open dollarQuote state. + // Preserve prior behavior by rejecting unmatched ')' + // when command substitution parsing is enabled. + if !dollarQuote { + return nil, errors.New("invalid command line string") } + + out, err := shellRun(backtick, p.Dir) + if err != nil { + return nil, err + } + + // Defensive guard: valid $(...) implies the buffer must contain + // the "$(" prefix plus the collected command body. + if len(buf) < len(backtick)+2 { + return nil, errors.New("invalid command line string") + } + + buf = buf[:len(buf)-len(backtick)-2] + out backtick = "" - dollarQuote = !dollarQuote + dollarQuote = false continue } + + // Backtick parsing disabled: + // A bare ')' is a syntax error, consistent with '(' handling. + // Only close an already-open $(...) region. + if !dollarQuote { + return nil, errors.New("invalid command line string") + } + + buf += string(r) backtick = "" - dollarQuote = !dollarQuote + dollarQuote = false + got = argSingle + continue } + case '(': if !singleQuoted && !doubleQuoted && !backQuote { if !dollarQuote && strings.HasSuffix(buf, "$") { @@ -221,6 +253,7 @@ loop: return nil, errors.New("invalid command line string") } } + case '"': if !singleQuoted && !dollarQuote { if doubleQuoted { @@ -229,6 +262,7 @@ loop: doubleQuoted = !doubleQuoted continue } + case '\'': if !doubleQuoted && !dollarQuote { if singleQuoted { @@ -237,6 +271,7 @@ loop: singleQuoted = !singleQuoted continue } + case ';', '&', '|', '<', '>': if !(escaped || singleQuoted || doubleQuoted || backQuote || dollarQuote) { if r == '>' && len(buf) > 0 { diff --git a/vendor/github.com/mattn/go-shellwords/util_posix.go b/vendor/github.com/mattn/go-shellwords/util_posix.go index b56a90120a..4d6b924bbe 100644 --- a/vendor/github.com/mattn/go-shellwords/util_posix.go +++ b/vendor/github.com/mattn/go-shellwords/util_posix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package shellwords diff --git a/vendor/github.com/mattn/go-shellwords/util_windows.go b/vendor/github.com/mattn/go-shellwords/util_windows.go index fd738a7211..0a650f56b0 100644 --- a/vendor/github.com/mattn/go-shellwords/util_windows.go +++ b/vendor/github.com/mattn/go-shellwords/util_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package shellwords diff --git a/vendor/modules.txt b/vendor/modules.txt index 745e7f9461..e6dcf45796 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -381,7 +381,7 @@ github.com/manifoldco/promptui/screenbuf # github.com/mattn/go-runewidth v0.0.20 ## explicit; go 1.20 github.com/mattn/go-runewidth -# github.com/mattn/go-shellwords v1.0.12 +# github.com/mattn/go-shellwords v1.0.13 ## explicit; go 1.13 github.com/mattn/go-shellwords # github.com/mattn/go-sqlite3 v1.14.39