Skip to content

Commit 9c10fb3

Browse files
committed
fix: restrict cmd template function for remote dependency configs
Prevent arbitrary command execution from untrusted remote configuration dependencies by disabling the cmd template function when processing remote configs.
1 parent 1514b19 commit 9c10fb3

3 files changed

Lines changed: 33 additions & 0 deletions

File tree

pkg/skaffold/parser/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ func processEachDependency(ctx context.Context, d latest.ConfigDependency, cfgOp
347347
cfgOpts.file = path
348348
cfgOpts.selection = d.Names
349349
cfgOpts.isRemote = isRemoteCfg
350+
// Disable the `cmd` template function for remote/untrusted config dependencies
351+
// to prevent arbitrary command execution via malicious skaffold.yaml files.
352+
if isRemoteCfg {
353+
util.CmdAllowed = false
354+
defer func() { util.CmdAllowed = true }()
355+
}
350356
depConfigs, _, err := getConfigs(ctx, cfgOpts, opts, r)
351357
if err != nil {
352358
return nil, err

pkg/skaffold/util/env_template.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ var (
3737
funcsMap = template.FuncMap{
3838
"cmd": runCmdFunc,
3939
}
40+
// CmdAllowed controls whether the `cmd` template function is permitted.
41+
// Set to false when processing remote/untrusted config dependencies to
42+
// prevent arbitrary command execution.
43+
CmdAllowed = true
4044
)
4145

4246
// ExpandEnvTemplate parses and executes template s with an optional environment map
@@ -140,6 +144,9 @@ func MapToFlag(m map[string]*string, flag string) ([]string, error) {
140144
}
141145

142146
func runCmdFunc(name string, args ...string) (string, error) {
147+
if !CmdAllowed {
148+
return "", fmt.Errorf("the 'cmd' template function is not allowed in remote dependency configs for security reasons")
149+
}
143150
cmd := exec.Command(name, args...)
144151
out, err := RunCmdOut(context.TODO(), cmd)
145152
return strings.TrimSpace(string(out)), err

pkg/skaffold/util/env_template_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package util
1818

1919
import (
2020
"fmt"
21+
"strings"
2122
"testing"
2223

2324
"github.com/GoogleContainerTools/skaffold/v2/testutil"
@@ -180,6 +181,25 @@ func TestMapToFlag(t *testing.T) {
180181
}
181182
}
182183

184+
func TestCmdBlockedWhenNotAllowed(t *testing.T) {
185+
testutil.Run(t, "cmd blocked in remote config context", func(t *testutil.T) {
186+
t.Override(&CmdAllowed, false)
187+
_, err := ExpandEnvTemplate(`{{cmd "echo" "hello"}}`, nil)
188+
t.CheckError(true, err)
189+
if err != nil && !strings.Contains(err.Error(), "not allowed in remote dependency") {
190+
t.Errorf("expected 'not allowed in remote dependency' error, got: %v", err)
191+
}
192+
})
193+
194+
testutil.Run(t, "cmd allowed in local config context", func(t *testutil.T) {
195+
t.Override(&CmdAllowed, true)
196+
t.Override(&DefaultExecCommand, testutil.CmdRunOut("echo hello", "hello"))
197+
out, err := ExpandEnvTemplate(`{{cmd "echo" "hello"}}`, nil)
198+
t.CheckNoError(err)
199+
t.CheckDeepEqual("hello", out)
200+
})
201+
}
202+
183203
func TestRunCmdFunc(t *testing.T) {
184204
tests := []struct {
185205
description string

0 commit comments

Comments
 (0)