T09 · Insecure Skill Coding Practices
- Location
SKILL.md:253- Finding
Predictable State and Temporary Files Permit File Clobbering
- Content
View full analysis
"$FAILED_ITEMS" for item in "${ITEMS[@]}"; do if process_item "$item"; then ((PROCESSED++)) else ((FAILED++)) # Record the failed item jq --arg item "$item" --arg err "$?" '. += [{"item": $item, "error": $err}]' "$FAILED_ITEMS" > tmp && mv tmp "$FAILED_ITEMS" fi # Report progress every 10 items if (( PROCESSED % 10 == 0 )); then echo "$PROCESSED/$TOTAL completed ($(( PROCESSED * 100 / TOTAL ))%)" fi # Save a checkpoint every 50 items if (( PROCESSED % 50 == 0 )); then echo "{\"processed\": $PROCESSED, \"total\": $TOTAL}" > .batch-checkpoint.json fi done ``` ### Technical Analysis The executable Bash template writes to three predictable paths in the current working directory: - `failed.json` - `tmp` - `.batch-checkpoint.json` Shell redirection with `>` truncates an existing destination and follows symbolic links. The template does not verify file ownership, file type, or whether any destination is a symbolic link. It also does not ask before replacing existing state. The generic `tmp` name is not safely created and can collide with files from another process or batch run. It is also susceptible to pre-creation and symlink attacks. Concurrent executions can overwrite one another's temporary data and checkpoints. The issue is limited by the privileges of the account running the Skill: an attacker cannot use it to overwrite a file that the executing account cannot write. However, any writable target reachable through a prepared symbolic link may be affected. ### Attack Path 1. An attacker obtains the ability to create files in the directory where the user will execute the batch template. 2. The attacker creates `failed.json`, `tmp`, or `.batch- ...[truncated 1071 chars]- Remediation
View remediation
&2 exit 1 fi done ``` 3. Use `mktemp` in the same protected directory and atomically rename the completed file: ```bash temp_file=$(mktemp "$STATE_DIR/failed.json.tmp.XXXXXX") || exit 1 if jq --arg item "$item" --arg err "$status" \ '. += [{"item": $item, "error": $err}]' \ "$FAILED_ITEMS" > "$temp_file"; then chmod 600 "$temp_file" mv -- "$temp_file" "$FAILED_ITEMS" else rm -f -- "$temp_file" exit 1 fi ``` 4. Apply the same temporary-file and atomic-rename process to checkpoint writes. 5. Generate a unique state directory per batch to prevent concurrent jobs from sharing paths. 6. Detect existing state and require explicit confirmation before replacing it. 7. Avoid executing batch templates from untrusted or world-writable directories. ]]>
