Skip to content

Commit e73986e

Browse files
committed
Treat bare ')' as syntax error regardless of ParseBacktick
The merged security fix (#60) treated bare ')' as a literal when ParseBacktick=false, but as an error when ParseBacktick=true. Unify the behavior: bare ')' is always a syntax error, consistent with how bare '(' is already handled.
1 parent 9a78803 commit e73986e

2 files changed

Lines changed: 11 additions & 23 deletions

File tree

shellwords.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,15 @@ loop:
230230
}
231231

232232
// Backtick parsing disabled:
233-
// preserve literal text for $(...) constructs instead of
234-
// silently dropping the closing ')'.
235-
if dollarQuote {
236-
buf += string(r)
237-
backtick = ""
238-
dollarQuote = false
239-
got = argSingle
240-
continue
233+
// A bare ')' is a syntax error, consistent with '(' handling.
234+
// Only close an already-open $(...) region.
235+
if !dollarQuote {
236+
return nil, errors.New("invalid command line string")
241237
}
242238

243239
buf += string(r)
240+
backtick = ""
241+
dollarQuote = false
244242
got = argSingle
245243
continue
246244
}

shellwords_security_test.go

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,11 @@ func TestBareClosingParen_NoExecution_ReturnsError(t *testing.T) {
2727
}
2828
}
2929

30-
// Default behavior → ‘)’ is a literal; it does not break parsing
31-
func TestBareClosingParen_DefaultParsingLiteral(t *testing.T) {
32-
out, err := Parse(")a b)c d")
33-
if err != nil {
34-
t.Fatalf("unexpected error: %v", err)
35-
}
36-
37-
want := []string{")a", "b)c", "d"}
38-
if len(out) != len(want) {
39-
t.Fatalf("unexpected token count: got %d, want %d, out=%#v", len(out), len(want), out)
40-
}
41-
for i := range want {
42-
if out[i] != want[i] {
43-
t.Fatalf("unexpected token at %d: got %q, want %q, out=%#v", i, out[i], want[i], out)
44-
}
30+
// Default behavior → bare ‘)’ is a syntax error, consistent with ‘(‘ handling
31+
func TestBareClosingParen_DefaultParsingError(t *testing.T) {
32+
_, err := Parse(")a b)c d")
33+
if err == nil {
34+
t.Fatal("expected error for unmatched ‘)’, got nil")
4535
}
4636
}
4737

0 commit comments

Comments
 (0)