T09 · Insecure Skill Coding Practices
- Location
- dream-tools.sh:92
- Finding
- Unrestricted File Replacement Through the Atomic Write Command<![CDATA[ ## Vulnerability Details **File Location**: `dream-tools.sh`, lines 92–112 **Vulnerability Type**: Arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```bash cmd_atomic_write() { local target="${1:-}" local tmpfile="${2:-}" [[ -z "$target" || -z "$tmpfile" ]] && die "--atomic-write 需要 <target> <tmpfile>" [[ ! -f "$tmpfile" ]] && die "tmp 文件不存在:$tmpfile" # 若目标是 MEMORY.md,检查字符数上限 if [[ "$(realpath "$target" 2>/dev/null)" == "$(realpath "$MEMORY_MD" 2>/dev/null)" ]] || \ [[ "$target" == *"MEMORY.md" ]]; then local size size=$(wc -c < "$tmpfile" | tr -d ' ') if [[ $size -gt $MEMORY_HARD_LIMIT ]]; then die "写入中止:tmp 文件大小 ${size} 字符,超过硬上限 ${MEMORY_HARD_LIMIT}。请先压缩内容。" fi log "MEMORY.md 写入校验通过:${size}/${MEMORY_HARD_LIMIT} 字符" fi ensure_dir "$target" # mv 在同一文件系统上是原子操作 mv "$tmpfile" "$target" log "原子写入完成:$target" } ``` ### Technical Analysis The `--atomic-write` command accepts both the source and destination paths from command-line arguments. It validates only that the source exists. It does not constrain the destination to `MEMORY_MD`, `DREAM_VAULT_PATH`, or `OPENCLAW_WORKSPACE`. The `MEMORY.md` check imposes a size limit but is not an authorization check. For every other destination, the function creates the destination's parent directory and moves the supplied file into place without validating the canonical destination path. This contradicts the README claim that all file operations are strictly scoped to the Dream vault and OpenClaw workspace. Quoting the variables prevents shell metacharacter injection, but it does not prevent arbitrary path selection, traversal, symlink-based redirection, or replacement of unrelated files. ### Attack Path 1. An attacker or untrusted agent instruction creates a file containing attacker-selected data. 2. The attacker invokes the helper with that file and an arbitrary user-writable target: `` ...[truncated 1091 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Define an explicit allowlist of writable files rather than accepting arbitrary destinations. 2. Resolve the destination with `realpath` or `realpath -m` before writing. 3. Require the canonical destination to equal `MEMORY_MD` or be located beneath an explicitly approved canonical root. 4. Reject targets containing symlink components and revalidate immediately before replacement to reduce time-of-check/time-of-use risks. 5. Create the temporary file in the destination directory so the final rename remains atomic and cannot cross filesystem boundaries. 6. Ensure the source temporary file is owned by the current user and is not a symlink. 7. Use restrictive permissions for generated files and directories. For example: ```bash canonical_workspace=$(realpath -m "$WORKSPACE_PATH") canonical_vault=$(realpath -m "$DREAM_VAULT_PATH") canonical_target=$(realpath -m "$target") case "$canonical_target" in "$canonical_workspace/MEMORY.md"|"$canonical_vault"/*) ;; *) die "Destination is outside approved Dream paths" ;; esac [[ -L "$target" || -L "$tmpfile" ]] && die "Symlink paths are not allowed" ``` If the command is intended only for `MEMORY.md`, remove the destination argument entirely and always write to the predefined `MEMORY_MD` path. ]]>
