T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/statusline.sh:42
- Finding
- Predictable Temporary State File Allows Symlink-Based File Overwrite<![CDATA[ ## Vulnerability Details **File Location**: `scripts/statusline.sh:42-67` **Vulnerability Type**: Predictable temporary-file creation and unsafe symlink following **Risk Level**: Medium ### Vulnerable Code ```bash # Session state file (ephemeral, in /tmp) session_id="${session_id:-unknown}" state_file="/tmp/session-health-${session_id}.json" # Load previous state prev_pct=0 compactions=0 if [[ -f "$state_file" ]]; then if command -v jq &>/dev/null; then prev_pct=$(jq -r '.last_pct // 0' "$state_file" 2>/dev/null) || prev_pct=0 compactions=$(jq -r '.compactions // 0' "$state_file" 2>/dev/null) || compactions=0 else prev_pct=$(grep -o '"last_pct":[0-9]*' "$state_file" | cut -d: -f2) || prev_pct=0 compactions=$(grep -o '"compactions":[0-9]*' "$state_file" | cut -d: -f2) || compactions=0 fi fi # Detect compaction: usage dropped by more than COMPACTION_DROP points if [[ "$prev_pct" -gt 0 ]] && [[ $((prev_pct - used_pct)) -ge "$COMPACTION_DROP" ]]; then compactions=$((compactions + 1)) fi # Save state cat > "$state_file" <<EOF {"last_pct":${used_pct},"compactions":${compactions},"updated":"$(date -u +%Y-%m-%dT%H:%M:%SZ)"} EOF ``` The same predictable path is read by `scripts/context-check.sh:42-56`: ```bash state_file="/tmp/session-health-${session_id}.json" if [[ -f "$state_file" ]]; then if command -v jq &>/dev/null; then compactions=$(jq -r '.compactions // 0' "$state_file" 2>/dev/null) || compactions=0 # If no stdin data, use stored percentage if [[ -z "$used_pct" ]]; then used_pct=$(jq -r '.last_pct // empty' "$state_file" 2>/dev/null) || true fi else compactions=$(grep -o '"compactions":[0-9]*' "$state_file" | cut -d: -f2) || compactions=0 if [[ -z "$used_pct" ]]; then used_pct=$(grep -o '"last_pct":[0-9]*' "$state_file" | cut -d: -f2) || true fi fi fi ``` ### Technical Analysis The script stores session ...[truncated 2274 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Store state in a private per-user directory rather than directly in shared `/tmp`: ```bash state_dir="${XDG_RUNTIME_DIR:-$HOME/.cache}/session-health" umask 077 mkdir -p -- "$state_dir" chmod 700 -- "$state_dir" ``` 2. Restrict `session_id` to a safe character set or derive a fixed-length digest: ```bash safe_session_id=$(printf '%s' "$session_id" | sha256sum | cut -d' ' -f1) state_file="$state_dir/${safe_session_id}.json" ``` 3. Reject existing symbolic links and non-regular files. Verify that existing state is owned by the current user before reading it. 4. Write through a securely created temporary file and atomically rename it: ```bash tmp_file=$(mktemp "$state_dir/.state.XXXXXX") printf '{"last_pct":%s,"compactions":%s,"updated":"%s"}\n' \ "$used_pct" "$compactions" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$tmp_file" chmod 600 "$tmp_file" mv -f -- "$tmp_file" "$state_file" ``` 5. Validate loaded fields as bounded integers before arithmetic or status decisions. Reject malformed, negative, or unreasonable percentages and compaction counts. ]]>
