Back to skill

Security audit

wallpaper-auto-switch-pro-executable

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent macOS wallpaper utility, but its scripts contain confirmed command-injection risks and install a persistent LaunchAgent.

Review before installing. Only use trusted wallpaper directories and filenames, avoid paths containing shell or XML metacharacters, and do not install the LaunchAgent unless you understand it will keep running on a schedule. The unsafe scripting should be fixed before general use.

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

Error
Location
scripts/common.sh:8
Finding
Arbitrary Shell Command Execution Through Unsafe Path Expansion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/common.sh:8-13` **Vulnerability Type**: Shell command injection through `eval` **Risk Level**: High ### Vulnerable Code ```bash expand_path() { local input="$1" if [[ "$input" == ~* ]]; then eval "printf '%s' $input" else printf '%s' "$input" fi } ``` ### Technical Analysis The `expand_path` function passes a caller-controlled directory argument into `eval`. Although the intended behavior is tilde expansion, `eval` parses the resulting string as shell code. Consequently, command substitutions, variable expansions, redirections, separators, and other shell syntax contained in an argument beginning with `~` are evaluated. The function is reachable through `rotate_once.sh`, `list_images.sh`, and `install_launchagent.sh`. Quoting the argument when invoking these scripts does not prevent exploitation because the value is later reparsed by `eval`. ### Attack Path 1. An attacker persuades a user or agent to invoke one of the affected scripts with a crafted directory argument beginning with `~`. 2. The script assigns the untrusted argument to `DIR_INPUT`. 3. The script calls `expand_path "$DIR_INPUT"`. 4. `expand_path` constructs an `eval` expression containing the untrusted value. 5. Shell syntax embedded in the argument is evaluated before directory validation occurs. 6. The injected command executes as the user running the skill. The target directory does not need to pass `ensure_dir_exists` for command execution to occur because evaluation happens first. ### Impact Assessment Successful exploitation permits arbitrary command execution with the privileges of the current user. An attacker could read or modify files accessible to that user, access user-level secrets, install additional user-level persistence, or invoke other locally available applications and utilities. This issue does not independently provide root privileges, but it compromises the confidentiality, integrity, a ...[truncated 48 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Remove `eval` entirely and implement narrowly scoped tilde expansion with ordinary parameter substitution: ```bash expand_path() { local input="$1" case "$input" in "~") printf '%s' "$HOME" ;; "~/"*) printf '%s/%s' "$HOME" "${input#\~/}" ;; *) printf '%s' "$input" ;; esac } ``` Additional hardening should include: 1. Reject unsupported forms such as `~otheruser` unless they are explicitly required and resolved through a safe account lookup. 2. Continue quoting every path expansion at its point of use. 3. Validate that the resolved path is an expected directory after expansion. 4. Add regression tests using arguments containing command substitutions, semicolons, spaces, quotes, and newline characters, verifying that none are evaluated. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/common.sh:53
Finding
AppleScript Injection Through Malicious Image Filenames<![CDATA[ ## Vulnerability Details **File Location**: `scripts/common.sh:53-58` **Vulnerability Type**: AppleScript source injection **Risk Level**: High ### Vulnerable Code ```bash /usr/bin/osascript <<OSA set targetFile to POSIX file "$file" tell application "System Events" set picture of every desktop to targetFile end tell OSA ``` ### Technical Analysis The selected image path is embedded directly into dynamically generated AppleScript source. No AppleScript escaping is applied before the path is placed between double quotes. macOS filenames may contain quotation marks, newline characters, and other characters that can terminate the intended string and introduce additional AppleScript statements. AppleScript can invoke applications and execute shell commands through facilities such as `do shell script`, so this is a code-injection boundary rather than merely a filename parsing defect. The image path originates from filenames discovered under the user-selected directory. Recursive discovery means a malicious file can be placed in a nested directory as well. The vulnerable code is reached whenever `rotate_once.sh` selects such a file. ### Attack Path 1. An attacker places a file with a supported extension and an AppleScript-syntax filename in the configured wallpaper directory. 2. `collect_images` includes the file because selection is based on its extension. 3. `pick_random_image` eventually selects the maliciously named file. 4. `set_wallpaper_file` verifies only that the path identifies a regular file. 5. The path is inserted directly into the AppleScript source. 6. Embedded quotes and statements alter the generated program. 7. `osascript` executes the injected AppleScript as the current user. For an installed launch agent, the malicious file may be selected during any scheduled rotation, making exploitation asynchronous and potentially less visible. ### Impact Assessment Successful exploitation enables arbitrary AppleScript execution with t ...[truncated 528 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not interpolate filenames into AppleScript source. Pass the path as a positional argument and retrieve it from `argv`: ```bash /usr/bin/osascript - "$file" <<'OSA' on run argv set targetFile to POSIX file (item 1 of argv) tell application "System Events" set picture of every desktop to targetFile end tell end run OSA ``` The quoted heredoc delimiter prevents shell expansion, while the argument boundary ensures that the filename is treated as data rather than AppleScript source. Additional hardening should include: 1. Test filenames containing double quotes, backslashes, Unicode characters, spaces, and embedded newlines. 2. Use null-delimited file discovery and selection to avoid ambiguity from newline-containing filenames. 3. Consider canonicalizing the selected path and confirming that it remains within the configured wallpaper directory. 4. Treat directory contents as untrusted even when the directory itself was explicitly selected by the user. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/install_launchagent.sh:18
Finding
LaunchAgent Plist Injection Through Unescaped Filesystem Paths<![CDATA[ ## Vulnerability Details **File Location**: `scripts/install_launchagent.sh:18-41` **Vulnerability Type**: XML injection in generated launchd configuration **Risk Level**: Medium ### Vulnerable Code ```bash cat > "$LAUNCHD_PLIST" <<PLIST <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>${LAUNCHD_LABEL}</string> <key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>${SCRIPT_DIR}/rotate_once.sh</string> <string>${DIR_PATH}</string> </array> <key>StartInterval</key> <integer>$((INTERVAL_MINUTES * 60))</integer> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>${HOME}/Library/Logs/${LAUNCHD_LABEL}.log</string> <key>StandardErrorPath</key> <string>${HOME}/Library/Logs/${LAUNCHD_LABEL}.err.log</string> </dict> </plist> PLIST ``` ### Technical Analysis The script creates an XML property list by directly interpolating `SCRIPT_DIR`, `DIR_PATH`, and `HOME` into XML text. XML metacharacters such as `&`, `<`, and `>` are not escaped. A macOS directory name can contain these metacharacters. A crafted existing wallpaper directory can therefore terminate the surrounding `<string>` element and insert additional plist elements. Depending on the injected structure and property-list parser behavior, this can corrupt the configuration or introduce attacker-controlled launchd keys. The generated file is immediately passed to `launchctl bootstrap`, so no structural validation or inspection occurs between generation and attempted installation. ### Attack Path 1. An attacker creates or supplies an existing directory whose name contains crafted XML markup. 2. The user or agent invokes `install_launchagent.sh` with that directory. 3. `ensure_dir_exists` accepts it because it is a real directory. 4. The raw path is interpolated into the `<string>${DIR_PATH} ...[truncated 908 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Generate the plist through a structured serializer rather than textual interpolation. Suitable options include Python's `plistlib`, `/usr/libexec/PlistBuddy`, or another API that correctly encodes property-list strings. For example, a serializer should construct a dictionary containing: - `Label` - `ProgramArguments` as an array of literal path strings - `StartInterval` as an integer - `RunAtLoad` as a Boolean - `StandardOutPath` - `StandardErrorPath` Additional hardening should include: 1. Write the plist to a temporary file in the destination directory and atomically rename it into place. 2. Set restrictive file permissions, such as mode `0600`. 3. Validate the completed file with `plutil -lint` before calling `launchctl bootstrap`. 4. Remove the newly created plist if validation or bootstrap fails. 5. Canonicalize paths where appropriate, while preserving them as serialized data rather than executable or structural content. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
声明的核心功能是“立即换壁纸”或“安装定时轮换任务”,而该代码片段的实际功能只是读取本地目录、收集图片、统计数量并打印示例文件名。这属于与声明主目的明显不一致:代码没有调用任何 macOS 壁纸设置机制,也没有创建、写入或加载 launchd 配置。虽然访问本地壁纸目录与该技能主题相关,但这里只体现为辅助性的图片清单检查脚本,不能代表声明中的主要能力,因此应判定为描述与行为不匹配。

Vague Triggers

Medium
Confidence
89% confidence
Finding
The trigger phrases for immediate execution are broad everyday language and directly map user utterances to a local command that changes system state. In an agent setting, overly permissive triggers increase the chance of accidental activation or prompt-induced execution without a sufficiently explicit confirmation boundary.

Vague Triggers

Medium
Confidence
85% confidence
Finding
The folder-check phrases are somewhat ambiguous and can cause the agent to inspect arbitrary local directories based on loosely phrased requests. While the action is read-oriented rather than destructive, it still broadens access to local file metadata and can normalize execution on unclear intent.

Vague Triggers

Medium
Confidence
93% confidence
Finding
These broad install/uninstall automation triggers authorize creation or removal of a persistent launchd job from common-language requests. Persistence mechanisms are security-sensitive because they survive the current session and can be abused or triggered accidentally if the agent does not enforce explicit consent and precise scoping.

Session Persistence

Medium
Category
Rogue Agent
Content
输出:
1. 壁纸目录
2. 轮换间隔(分钟)
3. launchd plist 路径
4. 是否安装成功
5. 如何卸载
Confidence
87% confidence
Finding
The skill explicitly supports writing a launchd plist under the user's LaunchAgents directory, which establishes session persistence. Although persistence is the stated feature rather than covert behavior, persistence itself is security-relevant because it causes recurring execution and can be repurposed if the installed command or target path is not tightly controlled.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SUPPORTED_EXTENSIONS=(jpg jpeg png heic webp)
LAUNCHD_LABEL="com.openclaw.wallpaperrotator"
LAUNCHD_PLIST="$HOME/Library/LaunchAgents/${LAUNCHD_LABEL}.plist"

expand_path() {
  local input="$1"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The expand_path function uses eval on attacker-controlled input, which can trigger shell command execution during path expansion. In a skill that only needs to resolve local wallpaper paths, eval is unnecessary and materially increases risk because crafted input such as command substitution or shell metacharacters could execute arbitrary commands under the user's account.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The error message is hardcoded in Chinese, which forces a specific language for user-facing output without any opt-in or documented locale constraint. This can violate language/locale policy when the skill is intended for general use.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The error message is hardcoded in Chinese, which forces a specific language for user-facing output without any opt-in or documented locale constraint. This can violate language/locale policy when the skill is intended for general use.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The error message is hardcoded in Chinese, which forces a specific language for user-facing output without any opt-in or documented locale constraint. This can violate language/locale policy when the skill is intended for general use.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This shell script emits user-facing status and error text in Chinese, which imposes a specific language on all users. The file does not provide any opt-in, fallback, or justification for the locale restriction, so it conflicts with the language/locale policy criteria.

Session Persistence

Medium
Category
Rogue Agent
Content
mkdir -p "$HOME/Library/LaunchAgents"

cat > "$LAUNCHD_PLIST" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
Confidence
92% confidence
Finding
Writing a LaunchAgent plist into ~/Library/LaunchAgents is a persistence mechanism, because it prepares recurring execution under launchd for the current user. Although this aligns with the skill's stated purpose, persistence always increases attack surface if the plist or referenced script can be modified after installation.

Session Persistence

Medium
Category
Rogue Agent
Content
<string>${HOME}/Library/Logs/${LAUNCHD_LABEL}.err.log</string>
</dict>
</plist>
PLIST

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
launchctl bootstrap "gui/$(id -u)" "$LAUNCHD_PLIST"
Confidence
94% confidence
Finding
The script unloads any existing agent and bootstraps the new plist into the user's launchd domain, activating persistence immediately. In context this is expected functionality, but it remains security-sensitive because it registers recurring execution without additional integrity checks on the referenced script.

Session Persistence

Medium
Category
Rogue Agent
Content
</plist>
PLIST

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
launchctl bootstrap "gui/$(id -u)" "$LAUNCHD_PLIST"
launchctl enable "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true
launchctl kickstart -k "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true
Confidence
95% confidence
Finding
Enabling the launchd label makes the persistent agent active across future sessions, which is a classic persistence mechanism. The skill context makes this less suspicious than in unrelated software, but it is still a real persistence capability that could be leveraged if the installed components are replaced or modified.

Session Persistence

Medium
Category
Rogue Agent
Content
PLIST

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
launchctl bootstrap "gui/$(id -u)" "$LAUNCHD_PLIST"
launchctl enable "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true
launchctl kickstart -k "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true
Confidence
90% confidence
Finding
Kickstarting the label forces immediate execution of the persistent LaunchAgent, reducing the time between installation and code execution. In a wallpaper utility this is expected, but from a security perspective it means any unsafe or tampered referenced script runs right away under the user's session.

Session Persistence

Medium
Category
Rogue Agent
Content
launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
launchctl bootstrap "gui/$(id -u)" "$LAUNCHD_PLIST"
launchctl enable "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true
launchctl kickstart -k "gui/$(id -u)/${LAUNCHD_LABEL}" >/dev/null 2>&1 || true

echo "状态: 成功"
Confidence
95% confidence
Finding
The script explicitly enables a per-user launchd agent, creating session persistence that will automatically run on login and at intervals. In this skill's context, persistence is the intended feature for wallpaper rotation, but it is still security-relevant because it establishes recurring execution from a user-writable location and could be abused if the referenced script or directory is later tampered with.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The script emits user-facing status messages entirely in Chinese (for example at L14, L15, L18, and L22). This imposes a specific language on all users without opt-in or any documented justification, which matches the language/locale policy violation criteria.

Session Persistence

Medium
Category
Rogue Agent
Content
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/common.sh"

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
rm -f "$LAUNCHD_PLIST"

echo "状态: 成功"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/common.sh"

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
rm -f "$LAUNCHD_PLIST"

echo "状态: 成功"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/common.sh"

launchctl bootout "gui/$(id -u)" "$LAUNCHD_PLIST" >/dev/null 2>&1 || true
rm -f "$LAUNCHD_PLIST"

echo "状态: 成功"
Confidence
75% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Static analysis

No suspicious patterns detected.