T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/habit-tracker.sh:13
- Finding
- Path Traversal Enables Arbitrary File Creation and Modification## Vulnerability Details **File Location**: `scripts/habit-tracker.sh`, lines 13–47 **Vulnerability Type**: Path traversal and unsafe file handling **Risk Level**: High ### Vulnerable Code ```bash HABIT_NAME="$1" STATUS="${2:-check}" HABIT_FILE=".learnings/habits/${HABIT_NAME}.md" DATE=$(date +%Y-%m-%d) # 创建习惯文件(如果不存在) if [ ! -f "$HABIT_FILE" ]; then mkdir -p "$(dirname "$HABIT_FILE")" cat > "$HABIT_FILE" << EOF # 习惯追踪: $HABIT_NAME **开始日期**: $(date +%Y-%m-%d) **目标频率**: [填写] **当前阶段**: 启动期 ## 每日记录 EOF echo "✅ 创建新习惯文件: $HABIT_FILE" echo "📝 请编辑文件填写习惯详细信息" fi ``` The completion branch subsequently appends data to the same attacker-controlled path: ```bash case $STATUS in "yes"|"y"|"完成") # 记录完成 if grep -q "### $DATE" "$HABIT_FILE"; then echo "⚠️ 今天已经记录过此习惯" else cat >> "$HABIT_FILE" << EOF ### $DATE ✅ - **完成时间**: $(date +%H:%M) - **质量评分**: [1-10] - **备注**: [填写] EOF ``` ### Technical Analysis The first command-line argument is accepted as `HABIT_NAME` and inserted directly into `HABIT_FILE`. The script does not reject path separators, `..` components, absolute-path-like input, or symbolic-link destinations. Shell quoting prevents word splitting and shell command injection, but it does not prevent filesystem path traversal. A value such as `../../../../tmp/target` produces a path similar to: ```text .learnings/habits/../../../../tmp/target.md ``` Filesystem path normalization resolves the `..` components outside the intended `.learnings/habits` directory. The `mkdir -p`, `cat >`, `cat >>`, and `grep` operations then act on the escaped destination. If the destination is not recognized as an existing regular file, the initialization branch uses `cat >`, creating the file or truncating the resolved destination. If it exists, the status branches may append habit records using `cat >>`. S ...[truncated 1816 chars]
- Remediation
- ## Remediation Suggestions 1. **Apply strict allowlist validation to habit names.** Accept only a limited identifier format and reject all other input: ```bash HABIT_NAME="$1" if [[ ! "$HABIT_NAME" =~ ^[A-Za-z0-9_-]+$ ]]; then printf '%s\n' "Error: habit names may contain only letters, numbers, underscores, and hyphens." >&2 exit 1 fi ``` 2. **Use a fixed, canonical base directory.** Resolve the storage directory before constructing the destination and verify that the canonical destination remains inside it. ```bash BASE_DIR="$(pwd -P)/.learnings/habits" mkdir -p -- "$BASE_DIR" HABIT_FILE="$BASE_DIR/${HABIT_NAME}.md" ``` 3. **Reject symbolic-link destinations.** ```bash if [ -L "$HABIT_FILE" ]; then printf '%s\n' "Error: symbolic-link habit files are not allowed." >&2 exit 1 fi ``` Where available, perform file creation through an API or utility that supports no-follow and exclusive-creation semantics to avoid check-to-use races. 4. **Avoid unintended truncation.** Create new files atomically and refuse to overwrite existing destinations. Ensure that append operations are performed only after validating that the destination is a regular file owned or otherwise trusted by the current user. 5. **Use defensive shell settings and argument handling.** ```bash set -euo pipefail mkdir -p -- "$BASE_DIR" ``` 6. **Add regression tests** covering `../`, embedded `/`, absolute paths, newlines, symbolic links, and names beginning with `-`. Each test should verify that no file outside the canonical habits directory is created or modified.
