Back to skill

Security audit

Dynamic Island

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent macOS status widget, but it reads live OpenClaw session snippets and exposes them through underprotected local WebView/WebSocket mechanisms.

Review carefully before installing. Use only if you are comfortable with a local desktop process reading OpenClaw agent logs and showing recent prompt/response snippets. Avoid the LaunchAgent auto-start until the plist is included and reviewed, prefer a pinned virtual environment for Python dependencies, and harden the WebSocket/WebView path with authentication, origin checks, HTML escaping, and URL allowlists.

Vulnerability Patterns
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (6)

T06 · System Persistence

Error
Location
README.md:98
Finding

Optional Login Persistence Through LaunchAgent Registration

Content
View full analysis
~/Library/LaunchAgents/com.openclaw.face.plist launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist # Uninstall launchctl unload ~/Library/LaunchAgents/com.openclaw.face.plist rm ~/Library/LaunchAgents/com.openclaw.face.plist ``` ### Technical Analysis The documentation instructs users to place a property-list file in the per-user `~/Library/LaunchAgents` directory and load it through `launchctl`. A loaded LaunchAgent can execute its configured program automatically across login sessions. Persistent execution is not required for the Skill's core on-demand desktop status-monitoring functionality. The mechanism is presented as an optional auto-start feature and removal instructions are provided, but it still expands execution from an explicitly initiated run to automatic cross-session execution. The referenced `com.openclaw.face.plist` is absent from the audited artifact. Consequently, the installation command cannot create a functional service from this package as delivered: `sed` will fail to read the missing source file and may leave an empty destination file. The actual command, arguments, environment, and restart policy that would be registered therefore could not be reviewed. ### Attack Path 1. A user obtains or is later provided the referenced plist file. 2. The user follows the documented auto-start instructions. 3. The plist is copied into `~/Library/LaunchAgents`. 4. `launchctl load` registers and starts the configured process. 5. The configured executable continues to run automatically after future logins. 6. If the plist or referenced executable is subsequently replaced or compromised, attacker-controlled code can execute each time the us ...[truncated 521 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
server.py:125
Finding

Unauthenticated WebSocket Broadcasts Live Agent Conversation Snippets

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
index.html:441
Finding

Stored HTML Injection Through Agent Messages and Configuration Values

Content
View full analysis
`; html += `
${name}
`; // Add up to 2 latest messages const msgs = agentMessages.get(id) || []; const recent = msgs.slice(-2); for (const m of recent) { html += `
${m.text}
`; } html += ``; totalH += 30 + recent.length * 20; // agent row + messages } el.innerHTML = html; ``` Relevant session-derived data is stored for this rendering path: ```javascript if ((ev.type === 'message_received' || ev.type === 'done') && label && agent) { if (!agentMessages.has(agent)) agentMessages.set(agent, []); const q = agentMessages.get(agent); const prefix = ev.type === 'message_received' ? '你: ' : ''; q.push({ text: prefix + label, ts: Date.now() }); } ``` ### Technical Analysis The page constructs markup by concatenating several untrusted or externally editable values: - Session-derived user messages and assistant response previews in `m.text` - Agent names loaded from `config.json` - Agent IDs derived from directory names - Agent links loaded from `config.json` These values are inserted into element bodies and quoted attributes without HTML or attribute escaping, after which the entire string is assigned to `innerHTML`. Although script elements inserted through `innerHTML` generally do not execute, active HTML constructs such as event-handler at ...[truncated 1757 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
widget.swift:131
Finding

Native URL Bridge Opens Arbitrary Schemes Without Validation

Content
View full analysis
{ const group = e.target.closest('.agent-group[data-link]'); if (group) { try { window.webkit.messageHandlers.openURL.postMessage(group.dataset.link); } catch(ex) {} } }); ``` ### Technical Analysis The Swift handler accepts any string that `URL(string:)` can parse and passes it directly to `NSWorkspace.shared.open`. There is no allowlist for the intended Feishu/Lark scheme, no HTTPS host validation, and no rejection of local-file or unexpected custom application schemes. The immediate values normally originate from local `config.json`, but the unsafe HTML injection elsewhere in the page creates a route for attacker-controlled JavaScript to invoke the registered handler directly: ```javascript window.webkit.messageHandlers.openURL.postMessage(attackerControlledURI) ``` Custom URL schemes are dispatched to installed applications. Their effects depend on the receiving application and the security of its URL handler. ### Attack Path 1. An attacker obtains JavaScript execution in the WebView through the HTML injection vulnerability, or an attacker modifies `config.json`. 2. The attacker submits an arbitrary URI to `window.webkit.messageHandlers.openURL`. 3. The native Swift handler parses the URI without validating its scheme or destination. 4. `NSWorkspace.shared.open` dispatches the URI to the operating system. 5. A browser, local file handler, Feishu/Lark client, or another application registered for the chosen custom scheme i ...[truncated 672 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
start.sh:7
Finding

Predictable PID Files and Broad Process-Killing Logic

Content
View full analysis
/dev/null rm -f "$pf" fi done # Fallback: kill by port / process name / all widget processes lsof -ti:7788 -ti:7789 2>/dev/null | xargs kill -9 2>/dev/null pkill -f "swift.*widget" 2>/dev/null pkill -f "widget-compiled" 2>/dev/null echo "[openclaw-face] stopped" } ``` ### Technical Analysis The script stores process IDs in predictable paths under the shared `/tmp` namespace. Before calling `kill`, it does not verify: - Ownership of the PID file - Whether the file is a regular, non-symlink file - Whether its contents are a valid PID - Whether the referenced process belongs to the current user - Whether the process is actually this project's server or widget The fallback logic also force-kills every process listening on ports `7788` or `7789`, even if that process is unrelated. The `pkill -f` expressions match command lines rather than a verified executable identity and may terminate unrelated Swift or widget processes. On a normal multi-user macOS system, signaling another user's processes is constrained by operating-system permissions. However, an attacker or process operating under the same user account can manipulate the predictable PID files or arrange matching processes. ### Attack Path 1. A same-user attacker creates or replaces one of the predictable PID files in `/tmp`. 2. The attacker writes the PID of another process owned by that user into the file. 3. The victim runs `./start.sh`, `./start.sh stop`, or `./start.sh restart`. 4. The `stop` function reads the attacker-selected PID and calls `kill`. 5. Alternatively, an unrelated process uses ports `7788`/ ...[truncated 538 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
setup.sh:35
Finding

Unpinned Third-Party Dependency Installed Into the User Environment

Content
View full analysis
/dev/null; then echo "📦 安装 websockets..." pip3 install websockets fi echo "✅ websockets 已安装" ``` ```text websockets>=12.0 ``` The same unrestricted installation instruction also appears in `README.md:43-45` and `xiaohongshu-guide.md:53-55`: ```bash pip3 install websockets ``` ### Technical Analysis The setup script asks `pip3` to install the latest version of `websockets` available from the user's configured package index. It does not use the provided requirements file, an exact version, dependency hashes, or an isolated virtual environment. The requirements constraint `websockets>=12.0` allows every future release. Therefore, installation is not reproducible and can change after the Skill has been reviewed. The outcome also depends on the user's pip index configuration. The dependency name is not an apparent typo or dependency-confusion target within the audited evidence, and no malicious package was found in the artifact. The risk is the uncontrolled supply-chain and environment modification rather than a confirmed malicious dependency. ### Attack Path 1. A user runs `setup.sh` on a system where `websockets` is not already importable. 2. The script invokes the ambient `pip3` executable without an isolated environment or locked input. 3. Pip resolves the package and transitive dependencies from the configured index. 4. A compromised package release, compromised index, maliciously configured index, or incompatible future version is selected. 5. Package installation behavior executes with the privileges of the current user. 6. The subsequently installed package is imported by `server.py` and runs inside the long-lived monitoring process. ### Impact Assessment A comprom ...[truncated 442 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (33)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · README.md (reported line 108)May include surrounding context.

Uninstall

launchctl unload ~/Library/LaunchAgents/com.openclaw.face.plist rm ~/Library/LaunchAgents/com.openclaw.face.plist

text

## Architecture

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 131)May include surrounding context.

Uninstall

launchctl unload ~/Library/LaunchAgents/com.openclaw.face.plist rm ~/Library/LaunchAgents/com.openclaw.face.plist

text

## Architecture

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly monitors agent session files and exposes the latest messages in a desktop widget, but the README provides no privacy warning, consent guidance, or discussion of sensitive data handling. This can lead users to surface confidential prompts, responses, or identifiers on-screen or over local services without understanding the exposure risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The README describes the skill primarily as a macOS Dynamic Island-style widget that monitors agent session files and displays live status. Opening Feishu chat links on click introduces an external application/deep-link launching capability that is not necessary for basic status display and monitoring.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 103)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 104)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 107)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 108)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 121)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 122)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 130)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 131)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · README.md (reported line 104)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall
launchctl unload ~/Library/LaunchAgents/com.openclaw.face.plist

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · xiaohongshu-guide.md (reported line 122)May include surrounding context.

bash
# Install Launch Agent
sed "s|__INSTALL_DIR__|$(pwd)|g" com.openclaw.face.plist > ~/Library/LaunchAgents/com.openclaw.face.plist
launchctl load ~/Library/LaunchAgents/com.openclaw.face.plist

# Uninstall
launchctl unload ~/Library/LaunchAgents/com.openclaw.face.plist

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger list is broad and includes short natural-language phrases in multiple languages, which increases the chance of accidental or contextually inappropriate activation. In an agent ecosystem, ambiguous triggers can cause the skill to launch when the user is discussing the feature rather than intentionally invoking it, leading to unintended local script execution paths described in the skill.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The instruction to say phrases like “启动灵动岛” or “打开 dynamic island” is ambiguous natural-language activation guidance rather than a precise command contract. This raises the risk of unintended invocation from conversational text, especially because the skill can start local services and UI components when activated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The HTML declares lang="zh", and the visible UI strings throughout the page are Chinese-only, indicating the skill is fixed to a specific language. The policy requires either user opt-in/choice or a clearly documented justification for a locale constraint, neither of which appears in this file.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code emits user-visible text such as "[发送了一张图片]" and "[发送了文件]" directly in a single language. The file contains no indication that the skill is China-specific or that users can opt into this locale, which violates the language/locale policy requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The WebSocket events include visible labels like "正在调用工具…", "正在使用工具…", and "工具调用出错". Because these strings are forced for all users and no language-selection mechanism or justification is present, they constitute a natural-language locale policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · server.py (reported line 345)May include surrounding context.

python
await broadcast_queue.put(event)
                    # Play sound for done/error
                    if event["type"] == "done":
                        subprocess.Popen(["afplay", "/System/Library/Sounds/Glass.aiff"])
                    elif event["type"] == "task_error":
                        subprocess.Popen(["afplay", "/System/Library/Sounds/Basso.aiff"])

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

With no manifest available, the file-level docstring is the best available statement of intent: it describes an HTTP/WebSocket server that monitors session JSONL files and pushes state events. Spawning afplay subprocesses to play local sounds is an additional host-execution capability not described in that intent and not required to serve pages, watch files, or broadcast events.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · server.py (reported line 347)May include surrounding context.

python
if event["type"] == "done":
                        subprocess.Popen(["afplay", "/System/Library/Sounds/Glass.aiff"])
                    elif event["type"] == "task_error":
                        subprocess.Popen(["afplay", "/System/Library/Sounds/Basso.aiff"])

        # If idle for 10+ seconds after activity, send idle
        if had_activity is False and (now - idle_since) > 10:

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Multiple user-facing messages are hardcoded in Chinese, including error and completion output, with no opt-in or alternative locale. This can violate language or locale policy where skills should not force a specific language on users without choice or documented justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The stop logic uses broad and forceful termination mechanisms (kill -9 via xargs, plus pkill -f on generic process-name patterns) that can terminate unintended processes beyond those started by this script. In the context of a local widget/server launcher, this creates a real safety and availability risk because unrelated services using the same ports or matching those process patterns could be killed without confirmation or verification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The WKWebView registers an openURL script message handler and directly passes any string from embedded web content to NSWorkspace.shared.open without validating the scheme, origin, or requiring user consent. Any content loaded into the widget, including compromised localhost content, could cause the host to open arbitrary http/https/file/custom-scheme URLs and trigger external apps or unsafe flows.

Content

No source excerpt is available for this finding.