Back to skill

Security audit

OpenClaw Coach

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches an OpenClaw coaching workflow, but it automatically sends local content to a fixed recipient and writes synced data without enough user control.

Review before installing. Configure or remove the hard-coded OpenClaw recipient, add confirmation before scheduled sends, validate tip filenames against an allowlist, and make document sync opt-in with clear overwrite behavior. Do not run the scheduled send scripts until the destination and file scope 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send-daily-tip.sh:33
Finding

Local Tip Content Is Sent to a Hard-Coded External Recipient

Content
View full analysis
/dev/null) VERSION=$(cat "$OBSIDIAN_PATH/latest-version.txt" 2>/dev/null) MESSAGE="🌅 早安!今日 OpenClaw 技巧分享:\n\n" MESSAGE+="📌 $TIP\n\n" MESSAGE+="$TIP_CONTENT\n" if [[ -n "$VERSION" ]]; then MESSAGE+="\n🔔 版本更新: $VERSION" fi ``` ### Technical Analysis Both message-sending scripts use the same fixed OpenClaw recipient identifier instead of obtaining the intended recipient from an installation-specific configuration or explicit user input. Consequently, every installation of the Skill attempts to send messages to that identifier. In `send-daily-tip.sh`, the transmitted message contains a tip name, the full contents of a Markdown file from the user's Obsidian directory, and locally stored version information. The fixed recipient is not identified in the documented setup workflow, and no first-use confirmation or recipient ownership validation occurs. This creates an unintended data-disclosure channel. Even if the identifier belongs to the original author or a legitimate user in one environment, it cannot safely represent users installing the Skill in other environments. ### Attack Path 1. A user installs or deploys the Skill without modifying its scripts. 2. The user or scheduler invokes `scripts/pick-daily-tip.sh` or `scripts/send-daily-tip.sh`. 3. The script reads local filenames and, fo ...[truncated 1095 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send-daily-tip.sh:9
Finding

Path Traversal in Daily Tip Filename Can Disclose Files Outside the Tips Directory

Content
View full analysis
/dev/null) if [[ -z "$TIP" || "$TIP" == "null" ]]; then echo "❌ 今日技巧未选择,请在晚上 21:05 选择" exit 1 fi # 读取技巧详细内容 TIP_CONTENT=$(cat "$OBSIDIAN_PATH/tips/$TIP.md" 2>/dev/null) ``` The resulting content is subsequently transmitted: ```bash MESSAGE="🌅 早安!今日 OpenClaw 技巧分享:\n\n" MESSAGE+="📌 $TIP\n\n" MESSAGE+="$TIP_CONTENT\n" if [[ -n "$VERSION" ]]; then MESSAGE+="\n🔔 版本更新: $VERSION" fi # 通过 OpenClaw 发送消息给用户 openclaw message send --target "ou_6492d43062b301922db4bb3b91f2c22a" --message "$MESSAGE" ``` ### Technical Analysis The `TIP` value is read from `daily-tips.json` and interpolated directly into a filesystem path. The script checks only whether the value is empty or `null`; it does not reject path separators, `..` components, control characters, or values that are not members of the known tip list. Although the variable is shell-quoted and therefore does not create shell command injection, quoting does not prevent filesystem path traversal. A value such as: ```json { "2026-09-11": "../../Private/notes" } ``` causes the script to attempt to read: ```text $HOME/Obsidian/Docs/OpenClaw/tips/../../Private/notes.md ``` After path normalization, this resolves outside the intended `tips` directory. The `.md` suffix limits straightforward exploitation to paths that resolve with that suffix, but it still permits disclosure of readable Markdown files outside the approved directory. The contents are then included in a message sent through OpenClaw. The fixed recipient in the current code makes the traversal especially significant because selected file contents may be delivered to an unintended external account. ### Attack Path 1. An attacker or compromised pr ...[truncated 1629 chars]
Remediation
View remediation
&2 exit 1 fi ``` 2. Prefer validating the selected value against filenames actually enumerated from the trusted tips directory rather than relying only on a character pattern. 3. Canonicalize both the tips directory and selected file, then verify that the selected path remains inside the directory: ```bash TIPS_DIR="$OBSIDIAN_PATH/tips" TIP_FILE="$TIPS_DIR/$TIP.md" TIPS_ROOT=$(realpath "$TIPS_DIR") RESOLVED_TIP=$(realpath "$TIP_FILE" 2>/dev/null) || { echo "Tip file does not exist" >&2 exit 1 } case "$RESOLVED_TIP" in "$TIPS_ROOT"/*) ;; *) echo "Tip path escapes the tips directory" >&2 exit 1 ;; esac TIP_CONTENT=$(cat -- "$RESOLVED_TIP") ``` 4. Check that the selected path is a regular file and consider rejecting symbolic links: ```bash [[ -f "$RESOLVED_TIP" && ! -L "$TIP_FILE" ]] || exit 1 ``` 5. Create and update `daily-tips.json` atomically with restrictive permissions so unrelated local processes or users cannot modify it. 6. Treat malformed JSON, missing files, unreadable files, and empty content as fatal errors instead of silently continuing. 7. Remove the hard-coded outbound target and require explicit recipient configuration to prevent traversal-selected content from being sent to an unintended account. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code generally aligns with part of the declared purpose: it routes events for document sync, tip selection, and tip sending. However, the declared description includes a fourth capability—detecting OpenClaw version updates and reminding the user—that is not represented in this dispatcher at all. Additionally, the code chunk itself does not substantiate key specifics such as syncing from the official site to Obsidian; it only calls another script by name. Since the evaluation is based on the supplied chunk, the description is broader than what the code demonstrates, creating a partial mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

This code chunk is only a partial implementation of one declared feature, and even that feature is not fully aligned. The description says the skill lets the user choose a topic at 21:05, but the script merely sends a multiple-choice message and preemptively records the first randomly selected tip as tomorrow's value; it does not process any user response. It also directly messages a hard-coded target via openclaw message send, which is a concrete outbound messaging behavior absent from the declared permissions/triggers. While partial code alone does not always imply mismatch, the actual behavior here is materially narrower and somewhat different from the declared capability.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code partially matches the declared purpose: it does perform document synchronization into an Obsidian path and it retrieves latest release version information. However, several significant declared behaviors are absent from the supplied code: there is no functionality to send daily tips, no evening user prompt, and no actual reminder/notification for version updates. Additionally, the description says docs are synced from the official website, while the code explicitly pulls markdown files from GitHub raw content. Because these are core declared capabilities rather than incidental implementation details, the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill declares shell-backed behavior and scheduled execution but does not declare any explicit tool scope, permissions, or allowed-tools. This creates a confused-deputy risk where the runtime may grant broader execution than the user expects, especially because the skill can launch scripts that write into the user's knowledge base and potentially perform network access indirectly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill advertises automatic synchronization into the user's Obsidian knowledge base without warning that external content will be imported and written locally on a schedule. That omission matters because synced documentation could overwrite notes, introduce untrusted content into a personal knowledge base, or create privacy and integrity issues if users do not understand the automation scope.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The event handlers are defined with generic trigger names such as 'sync', 'pick-tip', and 'send-tip' without any visible authentication, provenance checks, or guard conditions. In a skill that runs shell scripts automatically, underspecified triggers increase the chance of unintended or unauthorized execution, causing unsolicited messaging, unwanted file writes, or repeated network sync operations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script's natural-language content, including comments and user-facing message text, is entirely in Chinese and does not offer any language or locale choice. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless clearly justified.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script claims to let the user choose tomorrow's tip, but it writes tomorrow's selection to the JSON file before any user response is collected. This creates deceptive behavior: downstream automation may act on a preselected tip while the user believes their later reply determines the result, undermining consent and workflow integrity.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The comment says the script records options for tomorrow's sending, but the code actually records only the first selected option as the final tip. This mismatch can hide unintended behavior from maintainers and users, making the user-choice feature effectively nonfunctional and increasing the chance of silent misuse.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sends content to a hardcoded external target identifier without any runtime disclosure or confirmation. In a scheduled coaching skill, silent outbound messaging can surprise users, misdirect content, or leak behavioral metadata if the target is incorrect, stale, or controlled by someone other than the intended recipient.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script sends the contents of locally stored tip and version files to a hard-coded external recipient ID without any validation, preview, or per-send user confirmation. Because the transmitted message is composed from local files under the user's Obsidian directory, any unintended or malicious modification of those files could cause private or unreviewed content to be exfiltrated automatically on a schedule.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script silently downloads remote content from GitHub and overwrites local Markdown files in the user's Obsidian knowledge base without integrity checks, explicit consent at runtime, or safe-write protections. In this skill's context of scheduled automatic execution, a compromised upstream repository, MITM on a misconfigured system, or unexpected content change could poison the user's notes or replace trusted documentation without notice.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/sync-docs.sh (reported line 67)May include surrounding context.

sh
done

# 获取版本信息
VERSION=$(curl -s "https://api.github.com/repos/openclaw/openclaw/releases/latest" 2>/dev/null | grep -oE '"tag_name": "[^"]+"' | cut -d'"' -f4)
if [[ -n "$VERSION" ]]; then
    echo "$VERSION" > "$OBSIDIAN_PATH/latest-version.txt"
fi

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This shell script contains natural-language strings only in Chinese, including the file comment and the unknown-event message. The policy requires avoiding a forced language or locale unless the user is offered a choice or the constraint is clearly documented and justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

Line L35 overwrites daily-tips.json, which is a user-data-affecting file write. The script has comments describing the behavior for developers, but there is no user-facing prompt, warning, or visible disclosure before the write occurs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script's user-facing comments and message content are entirely in Chinese, including the outbound greeting and status text, with no indication that language selection is configurable or intentionally limited to a Chinese-only context. This can violate the language/locale policy when users are not given an explicit opt-in or documented rationale for the restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script's natural-language comments and console output are entirely in Chinese, which imposes a specific language on users without opt-in or explanation. Under the policy, locale or language constraints should either be optional or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.