T09 · Insecure Skill Coding Practices
- Location
scripts/update-cache.sh:9- Finding
Predictable Cache Paths Allow Symlink-Based File Overwrite
- Content
View full analysis
"$TEMP_FILE" # Convert JSONL to array, dedupe by slug, sort by title jq -s 'unique_by(.slug) | sort_by(.title | ascii_downcase)' "$TEMP_FILE" > "$CACHE_FILE" rm -f "$TEMP_FILE" ``` ### Technical Analysis The cache update script uses predictable file paths: - `data/.recipes-temp.jsonl` - `data/recipes.json` Shell output redirection follows symbolic links. The statement `> "$TEMP_FILE"` therefore truncates the destination of a preexisting symbolic link. Likewise, redirection to `"$CACHE_FILE"` can overwrite the destination of a symbolic link placed at `data/recipes.json`. An attacker must first have sufficient access to create or replace entries in the project's `data` directory. If that condition is met, the attacker can cause the script to overwrite any file writable by the account running the skill. The use of quoted paths prevents ordinary shell word splitting but does not protect against symbolic-link attacks or time-of-check/time-of-use replacement. ### Attack Path 1. An attacker obtains write access to the project's `data` directory, such as through an insecure shared workspace or overly permissive project permissions. 2. The attacker creates a symbolic link using one of the predictable paths. For example: ```bash mkdir -p data ln -s "$HOME/.config/example.conf" data/.recipes-temp.jsonl ``` 3. A user or AI agent runs: ```bash ./scripts/update-cache.sh ``` 4. Line 29 executes shell redirection against the symbolic link. 5. The shell follows the link and truncates the linked file before recipe data is written. 6. Alternatively, an attacker can link `data/recipes.json` to a target file, causing line 73 to replace its content ...[truncated 784 chars]- Remediation
View remediation
&2 exit 1 fi mkdir -p -- "$DATA_DIR" chmod 700 -- "$DATA_DIR" TEMP_FILE="$(mktemp "$DATA_DIR/.recipes-temp.XXXXXX")" trap 'rm -f -- "$TEMP_FILE"' EXIT HUP INT TERM # Populate TEMP_FILE here. if [[ -L "$CACHE_FILE" ]]; then echo "Error: Cache destination must not be a symbolic link" >&2 exit 1 fi FINAL_TEMP="$(mktemp "$DATA_DIR/.recipes-final.XXXXXX")" trap 'rm -f -- "$TEMP_FILE" "$FINAL_TEMP"' EXIT HUP INT TERM jq -s 'unique_by(.slug) | sort_by(.title | ascii_downcase)' \ "$TEMP_FILE" > "$FINAL_TEMP" chmod 600 -- "$FINAL_TEMP" mv -f -- "$FINAL_TEMP" "$CACHE_FILE" rm -f -- "$TEMP_FILE" trap - EXIT HUP INT TERM ``` For stronger protection in hostile shared directories, use operating-system APIs that reject symbolic links when opening files, or ensure the entire project and data directory are owned by and writable only by the trusted executing user. ]]>
