T09 · Insecure Skill Coding Practices
- Location
scripts/scaffold.sh:97- Finding
Arbitrary Command Execution Through Sed Template Injection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/scaffold.sh, lines 97-111
Vulnerability Type: GNU sed program injection leading to command execution
Risk Level: HighVulnerable Code
bash render_template() { local tmpl="$1" local out="$2" # Use @ as separator to avoid conflicts with / in paths and commands sed \ -e "s@{{GOAL_DESCRIPTION}}@${GOAL}@g" \ -e "s@{{METRIC_COMMAND}}@${METRIC}@g" \ -e "s@{{TARGET_VALUE}}@${TARGET}@g" \ -e "s@{{DIRECTION}}@${DIRECTION}@g" \ -e "s@{{DIRECTION_VERB}}@${DIRECTION_VERB}@g" \ -e "s@{{CONSTRAINTS}}@${CONSTRAINTS}@g" \ -e "s@{{MAX_ITERATIONS}}@${MAX_ITERATIONS}@g" \ "$tmpl" > "$out" }Technical Analysis
The script interpolates command-line values directly into double-quoted sed programs. The
--goal,--metric, and--constraintsvalues are not escaped before being placed in the replacement portion of a sed substitution.Quoting the shell variables prevents ordinary shell word splitting, but it does not make the resulting sed program safe. An attacker can provide delimiters and newline characters that terminate the intended substitution and introduce additional sed commands. GNU sed supports the
ecommand, which executes a shell command. Consequently, a malicious value can transform the generated sed script into one that runs arbitrary operating-system commands.A conceptual malicious value can have the following structure:
text replacement@g e attacker-controlled-command # trailing textThe injected
@gcloses the original substitution, the newline introduces a standalone GNU sedecommand, and the comment neutralizes the remaining generated text. Backslashes and ampersands can also alter replacement semantics, while an unescaped@can corrupt generation or terminate the expression.The issue affects values that are not restricted to safe character sets, particularly:
...[truncated 2048 chars]
- Remediation
View remediation
Remediation Suggestions
-
Do not construct sed source code by interpolating untrusted values. Replace the sed-based renderer with an implementation that passes template values as data rather than executable syntax. A small Python renderer using literal string replacement is appropriate:
bash python3 - "$tmpl" "$out" \ "$GOAL" "$METRIC" "$TARGET" "$DIRECTION" \ "$DIRECTION_VERB" "$CONSTRAINTS" "$MAX_ITERATIONS" <<'PY' import sys tmpl, out, goal, metric, target, direction, verb, constraints, maximum = sys.argv[1:] replacements = { "{{GOAL_DESCRIPTION}}": goal, "{{METRIC_COMMAND}}": metric, "{{TARGET_VALUE}}": target, "{{DIRECTION}}": direction, "{{DIRECTION_VERB}}": verb, "{{CONSTRAINTS}}": constraints, "{{MAX_ITERATIONS}}": maximum, } with open(tmpl, "r", encoding="utf-8") as source: content = source.read() for marker, value in replacements.items(): content = content.replace(marker, value) with open(out, "w", encoding="utf-8") as destination: destination.write(content) PY -
If sed must be retained, implement and test a dedicated escaping function for the replacement context. It must safely encode the selected delimiter, backslashes, ampersands, and embedded newlines. Merely choosing an uncommon delimiter is insufficient.
-
Validate all free-form inputs and reject control characters where multiline values are not explicitly required.
-
Add regression tests using values containing
@,&, backslashes, semicolons, command substitutions, and newline-delimited sed commands. Tests should verify both literal output and absence of side effects. -
Restore or package the referenced template files and fail explicitly if the template directory is unavailable. This addresses the separate functionality defect and allows the renderer to be tested under its intended execution cond ...[truncated 181 chars]
-
