T09 · Insecure Skill Coding Practices
- Location
SKILL.md:53- Finding
Shell Command Injection Through an Unquoted Project Directory Placeholder
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:52-53,SKILL.md:72-73,SKILL.md:83-89, andSKILL.md:98-104
Vulnerability Type: Shell command injection
Risk Level: HighThe affected instructions directly interpolate the
<project-dir>placeholder into commands that are sent to a shell running inside tmux.bash tmux new-session -d -s codex-<task-name> -e "TASK_TMPDIR=$TMPDIR" tmux send-keys -t codex-<task-name> 'cd <project-dir> && set -o pipefail && codex exec --full-auto --json "$(cat $TASK_TMPDIR/prompt)" | tee $TASK_TMPDIR/events.jsonl && echo "__TASK_DONE__"' Enterbash tmux new-session -d -s claude-<task-name> -e "TASK_TMPDIR=$TMPDIR" tmux send-keys -t claude-<task-name> 'cd <project-dir> && claude -p "$(cat $TASK_TMPDIR/prompt)" && echo "__TASK_DONE__"' Enterbash # OpenCode tmux new-session -d -s opencode-<task-name> -e "TASK_TMPDIR=$TMPDIR" tmux send-keys -t opencode-<task-name> 'cd <project-dir> && opencode run "$(cat $TASK_TMPDIR/prompt)" && echo "__TASK_DONE__"' Enter # Pi (separate temp dir) TMPDIR=$(mktemp -d) && chmod 700 "$TMPDIR" tmux new-session -d -s pi-<task-name> -e "TASK_TMPDIR=$TMPDIR" tmux send-keys -t pi-<task-name> 'cd <project-dir> && pi -p "$(cat $TASK_TMPDIR/prompt)" && echo "__TASK_DONE__"' EnterThe optional completion-notification examples repeat the vulnerable construction:
bash # Generic: touch a marker file tmux send-keys -t codex-<task-name> 'cd <project-dir> && codex exec --full-auto "$(cat $TASK_TMPDIR/prompt)" && touch $TASK_TMPDIR/done; echo "__TASK_DONE__"' Enter # macOS: system notification tmux send-keys -t codex-<task-name> 'cd <project-dir> && codex exec --full-auto "$(cat $TASK_TMPDIR/prompt)" && osascr ...[truncated 3404 chars]- Remediation
View remediation
Remediation Suggestions
- Do not interpolate
<project-dir>directly into shell command text. - Resolve the directory to an absolute path and verify that it exists and is a directory before creating the tmux session.
- Pass the validated path through a dedicated tmux environment variable.
- Quote that variable in the command interpreted by the pane's shell.
- Use
cd --so paths beginning with a hyphen cannot be interpreted as options. - Quote all temporary-directory references for defense in depth.
- Programmatically enforce the documented
[a-z0-9-]+restriction for task names.
A hardened Codex example is:
bash PROJECT_DIR=$(cd -- "$PROJECT_DIR" && pwd -P) || exit 1 [ -d "$PROJECT_DIR" ] || exit 1 tmux new-session -d -s "codex-$TASK_NAME" \ -e "TASK_TMPDIR=$TMPDIR" \ -e "PROJECT_DIR=$PROJECT_DIR" tmux send-keys -t "codex-$TASK_NAME" \ 'cd -- "$PROJECT_DIR" && set -o pipefail && codex exec --full-auto --json "$(cat "$TASK_TMPDIR/prompt")" | tee "$TASK_TMPDIR/events.jsonl" && echo "__TASK_DONE__"' EnterApply the same environment-variable and quoting pattern to the Claude Code, OpenCode, Pi, and completion-notification examples. Where supported, prefer launching the target process through an API that accepts an argument array and an explicit working directory rather than constructing shell command strings.
- Do not interpolate
