T09 · Insecure Skill Coding Practices
- Location
scripts/init_or_sync.sh:90- Finding
Tracked Workspace Symlinks Can Exfiltrate Arbitrary Readable Files
- Content
View full analysis
/dev/null || true)" if [ -n "$response_sha" ]; then gh api -X PUT "$api_path" \ -f message="Sync $remote_name from OpenClaw workspace" \ -f content="$content_b64" \ -f sha="$response_sha" >/dev/null else gh api -X PUT "$api_path" \ -f message="Add $remote_name from OpenClaw workspace" \ -f content="$content_b64" >/dev/null fi } ``` ```bash for f in "${FILES[@]}"; do if [ -f "$WORKSPACE_DIR/$f" ]; then upsert_remote_file "$WORKSPACE_DIR/$f" "$f" changed=true echo "Synced: $f" fi done ``` ### Technical Analysis The synchronization loop checks tracked paths with `-f`, but this test succeeds when the path is a symbolic link whose target is a regular file. The script does not reject symbolic links or verify that the canonical path remains inside `WORKSPACE_DIR`. The accepted path is passed to `upsert_remote_file`, where shell input redirection follows the symbolic link: ```bash base64 < "$file_path" ``` The target file is encoded and uploaded through the authenticated GitHub API. Consequently, a party capable of creating or replacing one of the seven tracked workspace entries can make the script upload any file readable by the user running the skill. Quoting prevents shell command injection, but it does not prevent filesystem redirection through symbolic links. ### Attack Path 1. An attacker obtains the ability to create or replace a file in the OpenClaw workspace, ...[truncated 1220 chars]- Remediation
View remediation
&2 exit 1 fi if [ -f "$path" ]; then resolved_path="$(realpath -- "$path")" resolved_workspace="$(realpath -- "$WORKSPACE_DIR")" case "$resolved_path" in "$resolved_workspace"/*) ;; *) echo "Tracked file resolves outside the workspace: $path" >&2 exit 1 ;; esac upsert_remote_file "$resolved_path" "$f" fi ``` Additional hardening should include: - Require every tracked entry to be a regular, non-symlink file. - Verify that each canonical path remains under the canonical workspace directory. - Consider requiring files to be owned by the invoking user. - Open files defensively with no-follow semantics where supported, rather than performing a check followed by a separate read. - Revalidate immediately before reading to reduce time-of-check/time-of-use race exposure. - Abort synchronization if a tracked entry has an unexpected filesystem type. ]]>
