T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/update-cache.sh:9
- Finding
- Predictable Cache Paths Allow Symlink-Based File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/update-cache.sh`, lines 9, 28–29, and 72–74 **Vulnerability Type**: Predictable temporary file and unsafe symbolic-link handling **Risk Level**: Medium ### Vulnerable Code ```bash TEMP_FILE="$DATA_DIR/.recipes-temp.jsonl" # Clear temp file > "$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
- <![CDATA[ ## Remediation Suggestions 1. Create the temporary file securely with `mktemp` rather than using a predictable name. 2. Restrict the data directory to the current user and reject it if it is a symbolic link. 3. Write the completed cache to a secure temporary file and atomically rename it into place. 4. Use a trap to remove temporary files on success, failure, or interruption. 5. Verify that the final cache destination is not a symbolic link before replacement. Example hardening pattern: ```bash set -euo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" DATA_DIR="$SCRIPT_DIR/../data" CACHE_FILE="$DATA_DIR/recipes.json" if [[ -L "$DATA_DIR" ]]; then echo "Error: Data directory must not be a symbolic link" >&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. ]]>
