Skip to content

Commit 0f5d1b3

Browse files
execute: avoid interpolating args into bash -c
1 parent 43266de commit 0f5d1b3

File tree

2 files changed

+25
-17
lines changed

2 files changed

+25
-17
lines changed

internal/execute/execute.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,18 @@ func NewExpression(expression string, args []string) Command {
3636

3737
// Run executes a Command with Bash and returns the error if there is one
3838
func (c Command) Run() error {
39-
var command string
39+
var bashArgs []string
40+
4041
if c.Expression != "" {
41-
// Expressions need to be invoked inside a Bash function, so variables like
42-
// $0 and $@ are available
43-
command = fmt.Sprintf("fn() { %s; }; fn %s", c.Expression, formatArgString(c.Args))
42+
script := fmt.Sprintf(`fn() { %s; }; fn "$@"`, c.Expression)
43+
bashArgs = append([]string{"-c", script, "asdf"}, c.Args...)
44+
} else if len(c.Args) > 0 {
45+
bashArgs = append([]string{"-c", `exec "$0" "$@"`, c.Command}, c.Args...)
4446
} else {
45-
// Scripts can be invoked directly, with args provided
46-
command = fmt.Sprintf("%s %s", c.Command, formatArgString(c.Args))
47+
bashArgs = []string{"-c", c.Command}
4748
}
4849

49-
cmd := exec.Command("bash", "-c", command)
50+
cmd := exec.Command("bash", bashArgs...)
5051

5152
if len(c.Env) > 0 {
5253
cmd.Env = MergeWithCurrentEnv(c.Env)
@@ -55,8 +56,6 @@ func (c Command) Run() error {
5556
}
5657

5758
cmd.Stdin = c.Stdin
58-
59-
// Capture stdout and stderr
6059
cmd.Stdout = c.Stdout
6160
cmd.Stderr = c.Stderr
6261

@@ -105,11 +104,3 @@ func SliceToMap(env []string) map[string]string {
105104

106105
return envMap
107106
}
108-
109-
func formatArgString(args []string) string {
110-
var newArgs []string
111-
for _, str := range args {
112-
newArgs = append(newArgs, fmt.Sprintf("\"%s\"", str))
113-
}
114-
return strings.Join(newArgs, " ")
115-
}

internal/execute/execute_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package execute
22

33
import (
44
"fmt"
5+
"io"
56
"os"
67
"os/exec"
78
"strings"
@@ -18,6 +19,22 @@ func TestNew(t *testing.T) {
1819
})
1920
}
2021

22+
func TestRun_NoArgInjection(t *testing.T) {
23+
tmp := t.TempDir()
24+
injected := tmp + "/injected"
25+
26+
payload := fmt.Sprintf(`http://x"; : > %s #`, injected)
27+
28+
cmd := New("git", []string{"clone", payload, tmp + "/noop"})
29+
cmd.Stdout = io.Discard
30+
cmd.Stderr = io.Discard
31+
_ = cmd.Run()
32+
33+
if _, err := os.Stat(injected); err == nil {
34+
t.Fatalf("injection succeeded: %s was created", injected)
35+
}
36+
}
37+
2138
func TestNewExpression(t *testing.T) {
2239
t.Run("Returns new command expression", func(t *testing.T) {
2340
cmd := NewExpression("echo", []string{"test string"})

0 commit comments

Comments
 (0)