T09 · Insecure Skill Coding Practices
- Location
scripts/generate-digest.sh:9- Finding
Path Traversal Through Unvalidated Date Argument
- Content
View full analysis
"$DIGEST_FILE" << EOF ``` ### Technical Analysis The command-line argument is documented as a date in `YYYY-MM-DD` format, but the script neither validates that format nor verifies that the resulting paths remain inside `$MEMORY_DIR`. The attacker-controlled `DATE` value is directly embedded in both `LOG_FILE` and `DIGEST_FILE`. Although the variables are correctly quoted and therefore do not permit shell command injection, quoting does not prevent filesystem traversal through `../` components. By supplying enough parent-directory components, a caller can make the source path resolve outside `$HOME/clawd/memory` and make the destination path resolve outside `$HOME/clawd/memory/digests`. The `.md` and `-digest.md` suffixes restrict which filenames can be targeted, but do not enforce the intended directory boundary. The script reads the selected source file through commands such as `wc`, `grep`, `sed`, and `awk`, then incorporates extracted content into a newly generated digest file. ### Attack Path 1. The attacker creates or identifies a readable file outside the memory directory whose name ends in `.md`. 2. The attacker supplies a traversal string instead of a valid date, for example: ```bash ./scripts/generate-digest.sh "../../../../../../tmp/source" ``` 3. After path normalization, `LOG_FILE` can resolve to `/tmp/source.md`, assuming a typical home-directory layout and ...[truncated 1364 chars]- Remediation
View remediation
&2 exit 1 fi ``` 2. Validate that the value represents a real calendar date: ```bash if ! parsed_date=$(date -u -d "$DATE" +%Y-%m-%d 2>/dev/null) || [[ "$parsed_date" != "$DATE" ]]; then echo "Error: Invalid calendar date" >&2 exit 1 fi ``` Use a platform-appropriate equivalent where GNU `date` is unavailable. 3. Resolve and verify the source and destination paths before accessing them. Their canonical paths must remain beneath the intended directories: ```bash MEMORY_DIR=$(realpath "$HOME/clawd/memory") DIGEST_DIR="$MEMORY_DIR/digests" mkdir -p "$DIGEST_DIR" LOG_FILE=$(realpath -m "$MEMORY_DIR/$DATE.md") DIGEST_FILE=$(realpath -m "$DIGEST_DIR/$DATE-digest.md") case "$LOG_FILE" in "$MEMORY_DIR"/*) ;; *) echo "Error: Source path escapes memory directory" >&2; exit 1 ;; esac case "$DIGEST_FILE" in "$DIGEST_DIR"/*) ;; *) echo "Error: Destination path escapes digest directory" >&2; exit 1 ;; esac ``` 4. Use restrictive creation permissions where digests may contain sensitive information: ```bash umask 077 ``` 5. Consider refusing to overwrite an existing digest unless the user explicitly supplies an overwrite option. If overwriting is required, write to a securely created temporary file in the digest directory and atomically rename it after successful generation. ]]>
