T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/gog_dormant_cleanup.sh:47
- Finding
- Predictable Temporary File Enables Local File Clobbering and Information Disclosure## Vulnerability Details **File Location**: `scripts/gog_dormant_cleanup.sh`, lines 47–65 **Vulnerability Type**: Unsafe predictable temporary file **Risk Level**: Medium ### Vulnerable Code ```bash { echo "$subject" echo "" echo "The following installed GOG games have not been played in the last ${CUTOFF_DAYS} days." echo "Consider uninstalling to free up disk space." echo "" printf "%-40s %-22s %s\n" "GAME" "LAST PLAYED" "INSTALL PATH" printf '%.0s-' {1..100}; echo echo "$dormant" | while IFS=$'\t' read -r name last path; do printf "%-40s %-22s %s\n" "$name" "$last" "$path" done echo "" echo "Generated by gog-dormant-cleanup on $(date -Iseconds)" } > /tmp/gog_dormant_email.txt body=$(cat /tmp/gog_dormant_email.txt) ``` The same persistent path is also disclosed at line 87: ```bash echo "himalaya not found; email not sent. Body saved to /tmp/gog_dormant_email.txt" ``` ### Technical Analysis The script writes its report to the fixed, predictable path `/tmp/gog_dormant_email.txt`. It does not use `mktemp`, perform exclusive file creation, verify that the destination is a regular file owned by the current user, establish restrictive permissions, or remove the file after processing. On systems where `/tmp` is shared, an unprivileged local attacker can pre-create this path as a symbolic link. Shell output redirection follows symbolic links, so running the script can truncate and replace the contents of another file writable by the victim. The exact target and consequences depend on the invoking user's permissions. The generated report contains game names, last-played timestamps, and local installation paths. Because the file remains after execution and its permissions depend on the process umask and operating-system defaults, it may also expose local filesystem information. Concurrent executions use the same path and can overwrite or read each other's reports. ### Attack ...[truncated 1470 chars]
- Remediation
- ## Remediation Suggestions Replace the fixed path with a securely created per-run temporary file, restrict permissions before creation, and ensure cleanup on every exit path: ```bash umask 077 tmp_email=$(mktemp "${TMPDIR:-/tmp}/gog_dormant_email.XXXXXX") || { echo "Failed to create temporary report file" >&2 exit 1 } trap 'rm -f -- "$tmp_email"' EXIT { echo "$subject" echo "" echo "The following installed GOG games have not been played in the last ${CUTOFF_DAYS} days." echo "Consider uninstalling to free up disk space." echo "" printf "%-40s %-22s %s\n" "GAME" "LAST PLAYED" "INSTALL PATH" printf '%.0s-' {1..100} echo while IFS=$'\t' read -r name last path; do printf "%-40s %-22s %s\n" "$name" "$last" "$path" done <<< "$dormant" echo "" echo "Generated by gog-dormant-cleanup on $(date -Iseconds)" } > "$tmp_email" body=$(cat -- "$tmp_email") ``` Additional hardening measures: 1. Keep the report entirely in memory when a temporary file is unnecessary. 2. If the report must remain available after an email failure, save it in a private user-owned directory rather than shared `/tmp`. 3. Do not print a stale fixed pathname in status messages; print the securely generated path only when intentional retention is required. 4. Retain `umask 077` or explicitly apply mode `0600` to files containing local paths or activity information. 5. Use a cleanup trap covering normal completion, errors, and signals. 6. Avoid privileged execution unless explicitly required, as the damage possible through file-clobbering defects is bounded by the invoking account's permissions.
