T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:53
- Finding
- Shell Command Injection Through an Unquoted Project Directory Placeholder## Vulnerability Details **File Location**: `SKILL.md:52-53`, `SKILL.md:72-73`, `SKILL.md:83-89`, and `SKILL.md:98-104` **Vulnerability Type**: Shell command injection **Risk Level**: High The 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__"' Enter ``` ```bash 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__"' Enter ``` ```bash # 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__"' Enter ``` The 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
- ## Remediation Suggestions 1. Do not interpolate `<project-dir>` directly into shell command text. 2. Resolve the directory to an absolute path and verify that it exists and is a directory before creating the tmux session. 3. Pass the validated path through a dedicated tmux environment variable. 4. Quote that variable in the command interpreted by the pane's shell. 5. Use `cd --` so paths beginning with a hyphen cannot be interpreted as options. 6. Quote all temporary-directory references for defense in depth. 7. 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__"' Enter ``` Apply 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.
