From b6cf6feafb835c60510223c6ce30a6d32093e234 Mon Sep 17 00:00:00 2001 From: datadog-bits-staging <264369727+datadog-bits-staging@users.noreply.github.com> Date: Sun, 8 Mar 2026 23:13:52 +0000 Subject: [PATCH 1/2] Update SHELL_FEATURES.md for tilde blocking Co-authored-by: AlexandreYang <49917914+AlexandreYang@users.noreply.github.com> --- SHELL_FEATURES.md | 2 +- interp/validate.go | 23 ++++++++++++++++--- .../environment/tilde_in_heredoc_allowed.yaml | 14 +++++++++++ .../tilde_in_variable_assignment_blocked.yaml | 10 ++++++++ .../environment/tilde_mid_word_allowed.yaml | 10 ++++++++ .../shell/environment/tilde_not_expanded.yaml | 10 ++++---- .../environment/tilde_path_not_expanded.yaml | 10 ++++---- .../environment/tilde_quoted_allowed.yaml | 12 ++++++++++ .../environment/tilde_username_blocked.yaml | 10 ++++++++ 9 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 tests/scenarios/shell/environment/tilde_in_heredoc_allowed.yaml create mode 100644 tests/scenarios/shell/environment/tilde_in_variable_assignment_blocked.yaml create mode 100644 tests/scenarios/shell/environment/tilde_mid_word_allowed.yaml create mode 100644 tests/scenarios/shell/environment/tilde_quoted_allowed.yaml create mode 100644 tests/scenarios/shell/environment/tilde_username_blocked.yaml diff --git a/SHELL_FEATURES.md b/SHELL_FEATURES.md index c96165ca..5a64a528 100644 --- a/SHELL_FEATURES.md +++ b/SHELL_FEATURES.md @@ -66,7 +66,7 @@ Blocked features are rejected before execution with exit code 2. - ✅ Line continuation: `\` at end of line - ✅ Comments: `# text` - ❌ Extended globbing: `@(pat)`, `*(pat)`, etc. -- ❌ Tilde expansion: `~`, `~/path` +- ❌ Tilde expansion: `~`, `~/path`, `~user` — rejected at validation (exit code 2) - ❌ Process substitution: `<(cmd)`, `>(cmd)` ## Execution diff --git a/interp/validate.go b/interp/validate.go index 9a5e9232..f9d4b6da 100644 --- a/interp/validate.go +++ b/interp/validate.go @@ -5,6 +5,7 @@ package interp import ( "fmt" + "strings" "mvdan.cc/sh/v3/syntax" ) @@ -14,6 +15,7 @@ import ( // so that disallowed features are caught early with a clear error message. func validateNode(node syntax.Node) error { var err error + hdocWords := make(map[*syntax.Word]bool) syntax.Walk(node, func(n syntax.Node) bool { if err != nil { return false @@ -110,6 +112,21 @@ func validateNode(node syntax.Node) error { if err != nil { return false } + if n.Hdoc != nil { + hdocWords[n.Hdoc] = true + } + + // Blocked tilde expansion (prevents host user info disclosure via os/user.Lookup). + // Heredoc bodies are excluded since they don't undergo tilde expansion. + case *syntax.Word: + if !hdocWords[n] && len(n.Parts) > 0 { + if lit, ok := n.Parts[0].(*syntax.Lit); ok { + if strings.HasPrefix(lit.Value, "~") { + err = fmt.Errorf("tilde expansion is not supported") + return false + } + } + } } return true }) @@ -119,9 +136,9 @@ func validateNode(node syntax.Node) error { // blockedSpecialParams are single-character parameter names that are not // supported in the safe-shell interpreter (positional params, $#, $0, $@, $*). var blockedSpecialParams = map[string]bool{ - "#": true, // $# - number of positional parameters - "!": true, // $! - PID of the last background command - "0": true, // $0 - name of the shell or script + "#": true, // $# - number of positional parameters + "!": true, // $! - PID of the last background command + "0": true, // $0 - name of the shell or script "1": true, "2": true, "3": true, "4": true, // $1-$9 - positional parameters "5": true, "6": true, "7": true, "8": true, "9": true, "@": true, // $@ - all positional parameters as separate words diff --git a/tests/scenarios/shell/environment/tilde_in_heredoc_allowed.yaml b/tests/scenarios/shell/environment/tilde_in_heredoc_allowed.yaml new file mode 100644 index 00000000..8f4e5535 --- /dev/null +++ b/tests/scenarios/shell/environment/tilde_in_heredoc_allowed.yaml @@ -0,0 +1,14 @@ +test_against_local_shell: false +description: Tilde inside heredoc body is allowed (heredocs do not undergo tilde expansion). +input: + script: |+ + cat < Date: Mon, 9 Mar 2026 00:14:45 +0100 Subject: [PATCH 2/2] Apply suggestion from @AlexandreYang --- SHELL_FEATURES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SHELL_FEATURES.md b/SHELL_FEATURES.md index 5a64a528..9ac4a531 100644 --- a/SHELL_FEATURES.md +++ b/SHELL_FEATURES.md @@ -66,7 +66,7 @@ Blocked features are rejected before execution with exit code 2. - ✅ Line continuation: `\` at end of line - ✅ Comments: `# text` - ❌ Extended globbing: `@(pat)`, `*(pat)`, etc. -- ❌ Tilde expansion: `~`, `~/path`, `~user` — rejected at validation (exit code 2) +- ❌ Tilde expansion: `~`, `~/path`, `~user` - ❌ Process substitution: `<(cmd)`, `>(cmd)` ## Execution