T09 · Insecure Skill Coding Practices
- Location
SKILL.md:63- Finding
Predictable Temporary File Enables Symlink Attacks and Data Corruption
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 63-66
Vulnerability Type: Predictable and unsafe temporary file usage
Risk Level: Mediumbash jq --arg date "$TODAY" --arg ts "$TIMESTAMP" --arg platform "$PLATFORM" \ --arg amount "$AMOUNT" --arg note "$NOTE" \ '.records += [{"date":$date,"timestamp":$ts,"platform":$platform,"amount":($amount | tonumber),"note":$note}]' \ "$INCOME_FILE" > tmp.json && mv tmp.json "$INCOME_FILE"Technical Analysis
The record operation writes its result to a fixed relative path named
tmp.json. The location is derived from the process's current working directory rather than a private data directory, and the file is created through ordinary shell redirection without exclusive-creation or symbolic-link protections.If another local user or process can modify the working directory, it can pre-create
tmp.jsonas a symbolic link. Shell redirection follows that link and truncates or overwrites its target using the privileges of the user running the Skill. The subsequentmvcan also replace the income database with the attacker-created symbolic link.Concurrent invocations use the same temporary path and read the same original database state. They can overwrite one another's temporary output or cause one invocation to move a file expected by another, resulting in lost records or operation failure.
Attack Path
- The victim invokes the documented income-recording command from a shared or attacker-writable working directory.
- Before invocation, a local attacker creates
tmp.jsonas a symbolic link to a file writable by the victim. - The shell follows the link while processing the output redirection and truncates or replaces the target's contents with JSON output.
- The
mvoperation moves the symbolic link to~/.daily-income-logger/data/income.json, potentially leaving the income database linked to the attacker-selected target. 5 ...[truncated 785 chars]
- Remediation
View remediation
Remediation Suggestions
- Create the temporary file inside the private data directory with
mktemp, rather than using a fixed relative name. - Register a trap to remove the temporary file on normal exit, interruption, or failure.
- Rename the temporary file only after
jqcompletes successfully. - Use a lock such as
flockaround the complete read-modify-write transaction to prevent lost updates. - Verify that the destination is a regular file and not a symbolic link before reading or replacing it.
- Keep the temporary file on the same filesystem as the destination so the final rename is atomic.
Example hardened pattern:
bash LOCK_FILE="$DATA_DIR/data/income.lock" ( flock -x 9 TMP_FILE=$(mktemp "$DATA_DIR/data/income.json.XXXXXX") || exit 1 trap 'rm -f "$TMP_FILE"' EXIT jq --arg date "$TODAY" --arg ts "$TIMESTAMP" \ --arg platform "$PLATFORM" --arg amount "$AMOUNT" --arg note "$NOTE" \ '.records += [{ "date": $date, "timestamp": $ts, "platform": $platform, "amount": ($amount | tonumber), "note": $note }]' "$INCOME_FILE" > "$TMP_FILE" || exit 1 chmod 600 "$TMP_FILE" mv -- "$TMP_FILE" "$INCOME_FILE" || exit 1 trap - EXIT ) 9>"$LOCK_FILE"- Create the temporary file inside the private data directory with
