T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:84
- Finding
- Arbitrary File Creation and Append via Unvalidated File Name<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 84-105 **Vulnerability Type**: Path traversal and arbitrary file write **Risk Level**: High ### Vulnerable Code ```bash wa_log() { TYPE="$1" # "group" or "dm" ID="$2" # JID or phone CONTENT="$3" # what to log FILE_NAME="${4:-context.md}" # context.md / decisions.md / notes.md # Sanitize ID SAFE_ID=$(echo "$ID" | tr '@.+' '---') BASE="$HOME/.openclaw/workspace/memory/whatsapp" # Pick the right directory if [ "$TYPE" = "group" ]; then FILE="$BASE/groups/$SAFE_ID/$FILE_NAME" else FILE="$BASE/dms/$SAFE_ID/$FILE_NAME" fi # Create file if missing if [ ! -f "$FILE" ]; then mkdir -p "$(dirname "$FILE")" touch "$FILE" fi # Append timestamped entry echo "[$(date -u +%Y-%m-%d\ %H:%M)] $CONTENT" >> "$FILE" } ``` ### Technical Analysis The fourth argument to `wa_log`, `FILE_NAME`, is used directly when constructing the destination path. Although comments describe an intended set of files such as `context.md`, `decisions.md`, and `notes.md`, the implementation does not enforce this allowlist. A caller can supply directory traversal components such as `../../`, or an absolute path. In shell path resolution, an absolute `FILE_NAME` does not necessarily discard the preceding string when concatenated this way, but traversal components can still escape the intended conversation directory. The subsequent `mkdir -p`, `touch`, and append redirection create or modify the resolved destination. The appended content is also caller-controlled. This turns a conversation-memory helper into a general file-append primitive within the operating-system account's writable filesystem. ### Attack Path 1. An attacker or compromised calling workflow influences the fourth argument passed to `wa_log`. 2. The attacker supplies a traversal path, for example: ```bash wa_log "dm" "+123456789" "attac ...[truncated 1095 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the free-form filename with an exact allowlist: ```bash case "$TYPE:$FILE_NAME" in group:context.md|group:decisions.md|group:people.md) ;; dm:context.md|dm:notes.md) ;; *) echo "Invalid memory file" >&2 return 1 ;; esac ``` 2. Reject filenames containing `/`, `\`, `..`, control characters, or leading path separators. 3. Canonicalize both the base directory and destination, then verify that the destination remains beneath the expected conversation directory. 4. Do not create arbitrary parent directories from user-provided path components. 5. Give the memory directory restrictive permissions, such as `0700` for directories and `0600` for files. 6. Treat `CONTENT` as untrusted data and ensure that memory files are never subsequently executed or sourced as shell code. 7. Add tests covering traversal strings, absolute paths, symbolic links, control characters, and invalid filenames. ]]>
