T09 · Insecure Skill Coding Practices
- Location
scripts/market-pulse.sh:73- Finding
Predictable Shared Temporary Output Permits Symlink-Based File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/market-pulse.sh, lines 73 and 385
Vulnerability Type: Unsafe temporary-file handling and symlink following
Risk Level: MediumVulnerable Code
Payment-required path at line 73:
bash echo '{"error":"payment_required","price":"0.03","currency":"USDC","network":"base","endpoint":"'${API_BASE}'/agent/v1/market/regime","method":"x402","docs":"https://www.x402.org"}' > /tmp/market-pulse-result.jsonSuccessful-result path at line 385:
javascript fs.writeFileSync('/tmp/market-pulse-result.json', JSON.stringify(json, null, 2));Technical Analysis
Both execution paths write to the fixed, publicly predictable pathname
/tmp/market-pulse-result.json. The script neither securely creates this destination nor verifies that it is a regular file owned by the invoking user. Shell redirection and Node.jsfs.writeFileSync()ordinarily follow symbolic links.On a multi-user system, another local user may create that pathname as a symbolic link before the Skill runs. The subsequent write then truncates and replaces the symlink target with generated JSON. Although the script securely creates its intermediate directory using
mktemp -d, it does not use that protected directory for its final output.Exploitation requires local access and knowledge of when the Skill will run. The attacker does not gain arbitrary file contents or direct code execution through this flaw alone because the data written is generated by the Skill. However, the attacker can target any existing file writable by the account executing the Skill.
Attack Path
- A local attacker identifies a file writable by the victim account.
- The attacker creates a symbolic link at the predictable destination:
bash ln -s /path/to/victim-writable-file /tmp/market-pulse-result.json - The victim invokes
scripts/market-pulse.sh. - Either the payment-required branch at line 73 or the successful-result branch at ...[truncated 945 chars]
- Remediation
View remediation
Remediation Suggestions
-
Write results inside the already-secure directory created with
mktemp -d:bash RESULT_FILE="$TMPDIR/market-pulse-result.json"Pass this path to Node.js through an environment variable or positional argument rather than embedding it in JavaScript source.
-
If the result must remain available after the cleanup trap runs, create a private per-user result directory with restrictive permissions:
bash RESULT_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/supah-pulse" install -d -m 700 "$RESULT_DIR" RESULT_FILE="$RESULT_DIR/market-pulse-result.json" -
Create a unique output file securely:
bash RESULT_FILE=$(mktemp "$RESULT_DIR/market-pulse-result.XXXXXX.json") chmod 600 "$RESULT_FILE" -
If a stable filename is required, write to a securely created temporary file in the same private directory and atomically rename it into place. Ensure the directory is not writable by other users.
-
Avoid relying only on a pre-write symbolic-link check, because checking and then opening the path introduces a time-of-check/time-of-use race. Use secure creation semantics that reject existing paths or use a private directory controlled exclusively by the invoking user.
-
Avoid running this Skill with elevated privileges. Its declared market-intelligence functionality does not require administrative access.
-
