Back to skill

Security audit

TODO Tracker (Safe)

Security checks for vulnerabilities and agentic risk

Overview

This TODO skill appears purpose-built rather than malicious, but its file handling is broader and less safe than advertised.

Review before installing if you use shared workspaces or set TODO_FILE manually. Prefer using the default private OpenClaw workspace path, avoid group/world-writable directories, and do not rely on this as a hardened multi-user-safe TODO store until the path, symlink, and temporary-file handling are fixed.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/todo.sh:100
Finding

Predictable Temporary Files Permit Symlink-Based File Overwrites

Content
View full analysis
"$tmp_file" && mv "$tmp_file" "$TODO_FILE" fi } ``` The same unsafe temporary-file construction is used elsewhere: ```bash local tmp_file="${TODO_FILE}.tmp.$$" awk -v section="$section" -v entry="$entry" '...' "$TODO_FILE" > "$tmp_file" && mv "$tmp_file" "$TODO_FILE" ``` ```bash local tmp_file="${TODO_FILE}.tmp.$$" grep -vF -- "$found_line" "$TODO_FILE" > "$tmp_file" && mv "$tmp_file" "$TODO_FILE" ``` ### Technical Analysis The temporary filename is derived from the destination path and the process ID: ```bash "${TODO_FILE}.tmp.$$" ``` Process IDs are predictable, and shell output redirection does not create the file exclusively or reject symbolic links. If the directory containing `TODO_FILE` is writable by another local user, that user can pre-create the predicted temporary path as a symbolic link. When the script performs: ```bash command > "$tmp_file" ``` the shell follows the symbolic link and truncates or overwrites its target with the privileges of the user running the script. The subsequent `mv` does not prevent the initial write from occurring. Using a PID suffix reduces accidental collisions but does not provide secure temporary-file creation. The script also has no cleanup trap, restrictive temporary-file mode, or verification that the temporary path is a newly created regular file. ### Attack Path 1. The victim configures `TODO_FILE` in a directory writable by an attacker, such as a shared workspace. 2. The attacker predicts or observes the PID of an upcoming `todo.sh` process. 3. The attacke ...[truncated 1128 chars]
Remediation
View remediation
"$tmp_file"; then chmod --reference="$TODO_FILE" "$tmp_file" 2>/dev/null || chmod 600 "$tmp_file" mv -f -- "$tmp_file" "$TODO_FILE" else rm -f -- "$tmp_file" return 1 fi ``` 7. Apply the secure helper consistently to every rewrite at lines 100, 139, 169, 176, and 208. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/todo.sh:48
Finding

Insufficient Path, Symlink, Ownership, and Permission Validation

Content
View full analysis
"$TODO_FILE" << EOF # TODO - 任务追踪 *最后更新:${DATE}* ## 🔴 高优先级 ## 🟡 中优先级 ## 🟢 低优先级 ## ✅ 已完成 --- ## 备注 EOF log_info "已创建 TODO 文件:$TODO_FILE" fi # 检查文件权限(不允许其他人可写) local perms perms=$(stat -c %a "$TODO_FILE" 2>/dev/null || stat -f %Lp "$TODO_FILE" 2>/dev/null || echo "644") local other_perm="${perms: -1}" if [[ "$other_perm" =~ [2367] ]]; then log_error "TODO 文件权限过于宽松:$perms(其他人可写)" return 1 fi } ``` The path is populated from an environment variable at line 13: ```bash TODO_FILE="${TODO_FILE:-${HOME}/.openclaw/workspace/TODO.md}" ``` ### Technical Analysis The script accepts an unrestricted environment-controlled `TODO_FILE` path. Its validation has several weaknesses: - It checks only whether the parent directory exists and is writable. - It does not verify that the parent directory is owned by the invoking user. - It does not reject group-writable or world-writable directories. - It does not reject symbolic links for `TODO_FILE`. - It follows symbolic links during `-f`, `stat`, input, and output operations. - It examines only the final octal permission digit, so group-writable files such as mode `664` are accepted. - If both `stat` variants fail, it silently assumes mode `644`. - File creation does not explicitly apply a restrictive mode. The creation branch is particularly unsafe for a dangling symbolic link. `[[ ! -f "$TODO_ ...[truncated 1984 chars]
Remediation
View remediation
"$TODO_FILE" ) 2>/dev/null || { log_error "Unable to create TODO_FILE safely" return 1 } ``` 9. Prefer a secure descriptor-based implementation or a language API supporting `O_CREAT | O_EXCL | O_NOFOLLOW`. 10. Validate the path again immediately before replacement to reduce time-of-check/time-of-use race exposure. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/todo.sh:25
Finding

Blacklist Sanitization Allows Persistent Multiline TODO Format Injection

Content
View full analysis
( ) { } [ ] ! # ~ local sanitized sanitized=$(printf '%s' "$input" | tr -d '$`\\|;&<>(){}[]!#~') # 限制长度 printf '%s' "${sanitized:0:200}" } ``` The sanitized value is inserted directly into the Markdown record: ```bash if [[ -z "$item" ]]; then log_error "任务内容不能为空" return 1 fi # 清理输入 item=$(sanitize_input "$item") init_todo || return 1 # 确定目标分区 local section="" case "$priority" in high) section="## 🔴 高优先级" ;; medium) section="## 🟡 中优先级" ;; low) section="## 🟢 低优先级" ;; esac local entry="- [ ] ${item} (添加:${DATE})" # 使用 awk 安全插入(不使用变量插值) local tmp_file="${TODO_FILE}.tmp.$$" awk -v section="$section" -v entry="$entry" ' BEGIN { inserted = 0 } $0 == section { print print entry inserted = 1 next } { print } END { if (!inserted) print "Warning: section not found" > "/dev/stderr" } ' "$TODO_FILE" > "$tmp_file" && mv "$tmp_file" "$TODO_FILE" ``` ### Technical Analysis The documentation describes the validator as allowing only letters, numbers, Chinese characters, spaces, and common punctuation. The implementation does not enforce such an allowlist. Instead, it deletes a small blacklist of characters. Newline, carriage-return, tab, escape, and other control characters are not removed. Consequently, a task argument can span multiple lines. The resulting value is embedded directly into the Markdown entry and passed to `awk` through `-v entry="$entry"`. An attacker can therefore inject additional lines that resemble TODO records or otherwise alter the document structure. Removing `#` makes direct Markdown heading injection less stra ...[truncated 2178 chars]
Remediation
View remediation
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The entire skill description is written in Chinese, including headings, feature descriptions, and usage guidance, with no indication that other languages are supported or that the locale restriction is intentional. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill title and description are presented in Chinese, and the document does not offer a language/locale choice or explain that the skill is intended only for a Chinese-speaking context. This creates a natural-language policy concern because it implicitly enforces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger list includes broad natural-language phrases such as 'what's on the TODO' and heartbeat auto-display behavior that may cause the skill to activate outside clearly intended task-management contexts. Unintended invocation can expose or modify task data, create confusing agent behavior, and increase the chance that unrelated user input is routed into file-manipulating functionality.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script's comments, log messages, help text, and status output are written in Chinese throughout, with no indication that the skill is intended only for Chinese-speaking users or that another language can be selected. This creates a natural-language policy concern because the file imposes a specific language/locale on users without opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.