feat(recipe): add safety whitelist for allowed shell commands

Implement a read-only command whitelist in the recipe loader to reject
potentially dangerous shell commands, ensuring only safe operations like
ls, pwd, cat, etc., are permitted. This enhances security by preventing
execution of unauthorized commands in recipes.
This commit is contained in:
Greg Gauthier 2026-03-07 17:11:13 +00:00
parent aedf9cdf03
commit 63e640c022

View File

@ -11,6 +11,21 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
// Global safe read-only whitelist
var safeReadOnlyCommands = map[string]bool{
"ls": true,
"pwd": true,
"cat": true,
"tree": true,
"git status": true,
"git log": true,
"find": true,
"grep": true,
"cndump -s": true,
"tea repos list -o csv -lm 100": true,
"tea repos search -o csv": true,
}
var ( var (
// stepRe still finds the headings (this one is solid) // stepRe still finds the headings (this one is solid)
stepRe = regexp.MustCompile(`(?m)^### Step (\d+): (.+)$`) stepRe = regexp.MustCompile(`(?m)^### Step (\d+): (.+)$`)
@ -32,6 +47,14 @@ func Load(path string, userParams map[string]any) (*Recipe, error) {
return nil, fmt.Errorf("yaml parse: %w", err) return nil, fmt.Errorf("yaml parse: %w", err)
} }
// === SAFETY CHECK: reject dangerous allowed_shell_commands ===
for _, cmd := range r.AllowedShellCommands {
trimmed := strings.TrimSpace(strings.ToLower(cmd))
if !safeReadOnlyCommands[trimmed] && !strings.HasPrefix(trimmed, "git status") && !strings.HasPrefix(trimmed, "git log") {
return nil, fmt.Errorf("\033[31mERROR: Recipe contains unsafe shell command: %q\033[0m\n\nOnly the following read-only commands are allowed:\n ls, pwd, cat, tree, git status, git log, find, grep\n\nRemove or replace the dangerous command and try again.", cmd)
}
}
// Apply defaults + user --param overrides // Apply defaults + user --param overrides
if r.Parameters == nil { if r.Parameters == nil {
r.Parameters = make(map[string]Parameter) r.Parameters = make(map[string]Parameter)