Back to skill

Security audit

Vector-Robot

Security checks for vulnerabilities and agentic risk

Overview

This robot-control skill is not clearly malicious, but it needs Review because it can control a physical robot and camera while shipping unsafe helper scripts, an unauthenticated proxy, and optional login persistence.

Install only if you intentionally want an agent to control your Vector robot and camera. Avoid enabling the LaunchAgent until the proxy is restricted to loopback, authenticated, and easy to uninstall; treat speech text and snapshot paths as unsafe inputs until the scripts are fixed; use robot movement only under supervision on a safe surface.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • 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 (5)

T06 · System Persistence

Error
Location
scripts/install-launchagent.sh:7
Finding

Persistent macOS LaunchAgent with automatic restart

Content
View full analysis
"$PLIST_PATH" << EOF Label com.openclaw.vector-proxy ProgramArguments $NODE_PATH $SCRIPT_DIR/proxy-server.js RunAtLoad KeepAlive WorkingDirectory $SCRIPT_DIR StandardOutPath $SCRIPT_DIR/proxy.log StandardErrorPath $SCRIPT_DIR/proxy-error.log EOF launchctl load "$PLIST_PATH" ``` ### Technical Analysis The installer creates a user-level LaunchAgent, enables `RunAtLoad`, enables continuous restart through `KeepAlive`, and immediately activates the service with `launchctl load`. The persistence is disclosed in `SKILL.md`, but it is not required for one-time robot control or manual use of the optional proxy. The LaunchAgent executes `proxy-server.js` directly from the mutable Skill directory. If that file, its directory, or the selected Node executable is subsequently replaced, the replacement code will execute automatically under the user's account and will be restarted by macOS. ### Attack Path 1. The user explicitly or inadvertently runs `scripts/install-launchagent.sh`. 2. The script writes `com.openclaw.vector-proxy.plist` into `~/Library/LaunchAgents`. 3. `launchctl load` activates the agent immediately. 4. `RunAtLoad` starts it in future login sessions, while `KeepAlive` restarts it after termination. 5. An ...[truncated 548 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vector-say.sh:7
Finding

Arbitrary Python code injection through speech text

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/vector-see.sh:6
Finding

Arbitrary Python code injection through camera output path

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/proxy-server.js:18
Finding

Unauthenticated proxy listens beyond the documented loopback interface

Content
View full analysis
{ res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.url === '/v1/chat/completions' && req.method === 'POST') { let body = ''; req.on('data', chunk => body += chunk); req.on('end', async () => { try { const data = JSON.parse(body); const messages = data.messages || []; const isStreaming = data.stream === true; const userMessage = messages.filter(m => m.role === 'user').pop(); const question = userMessage?.content || 'Hello'; const request = { timestamp: Date.now(), question, raw: data }; fs.writeFileSync(REQUEST_FILE, JSON.stringify(request, null, 2)); server.listen(PORT, () => { console.log(`Vector-OpenClaw proxy running on http://localhost:${PORT}`); console.log(`Configure wire-pod: Custom provider, endpoint http://localhost:${PORT}/v1`); }); ``` ### Technical Analysis Calling `server.listen(PORT)` without a host does not explicitly restrict the service to `127.0.0.1`, even though the log and documentation describe it as a localhost service. The completion route performs no API-key or authorization validation. Configuring wire-pod with the documented API key `openclaw` does not provide protection because the proxy never checks the `Authorization` header. Wildcard CORS permits requests from arbitrary browser origins. Consequently, any client able to reach t ...[truncated 1001 chars]
Remediation
View remediation
{ console.log(`Vector-OpenClaw proxy running on http://127.0.0.1:${PORT}`); }); ``` - Require and verify an unpredictable secret in the `Authorization` header. - Compare authentication values safely and reject unauthorized requests before reading large bodies. - Replace wildcard CORS with an explicit allowlist, or disable CORS if browser access is unnecessary. - Validate the `Host`, method, route, and `Content-Type`. - Do not use the documented constant `openclaw` as a security secret. - Apply local firewall restrictions if non-loopback operation is genuinely required. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/proxy-server.js:49
Finding

Unbounded request buffering and unsafe shared-file request correlation

Content
View full analysis
body += chunk); req.on('end', async () => { try { const data = JSON.parse(body); const messages = data.messages || []; const isStreaming = data.stream === true; const userMessage = messages.filter(m => m.role === 'user').pop(); const question = userMessage?.content || 'Hello'; console.log(`[${new Date().toISOString()}] Question: "${question}" (stream: ${isStreaming})`); const request = { timestamp: Date.now(), question, raw: data }; fs.writeFileSync(REQUEST_FILE, JSON.stringify(request, null, 2)); // Wait for response const startTime = Date.now(); const timeout = 25000; let response = null; while (Date.now() - startTime < timeout) { if (fs.existsSync(RESPONSE_FILE)) { try { const responseData = JSON.parse(fs.readFileSync(RESPONSE_FILE, 'utf8')); if (responseData.timestamp > request.timestamp - 1000) { response = responseData.answer; fs.unlinkSync(RESPONSE_FILE); break; } } catch (e) {} } await new Promise(r => setTimeout(r, 100)); } ``` ### Technical Analysis The server appends every incoming chunk to an in-memory string without imposing a maximum request size. A reachable client can therefore force excessive memory consumption and later cause a large synchronous disk write. All requests also share the same `request.json` and `response.json` files. Concurrent requests overwrite each other's request data. Responses are correlated only by comparing timestamps with a one-second tolerance, not by a unique request identifier. One request may consume a response intended for another request, while synchronous file operations block the Node.js event loop. # ...[truncated 869 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (19)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose is robot control, but the skill also introduces a proxy server, filesystem-based IPC, and an OpenAI-compatible bridge service not clearly reflected in the top-level description. That mismatch is dangerous because users and reviewers may authorize a robot-control skill without realizing it also exposes local HTTP functionality and persistent inter-process channels that expand the attack surface.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 90)May include surrounding context.

md
node scripts/proxy-server.js

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill documents shell commands, network access, environment variables, and local file interactions but declares no explicit tool scope or permissions. In an agent environment, this can grant broader-than-necessary capabilities to a skill that can control physical hardware and interact with local services, increasing the chance of unintended or unsafe actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The activation text includes broad phrases like wanting to 'speak through a robot' or 'control a physical robot,' which may match ordinary conversation and invoke a skill capable of movement, camera access, and speech output. Because this skill can affect real-world hardware, overbroad routing raises the risk of unintended activation and unsafe physical actions.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
77% confidence
Finding

The LaunchAgent instructions establish persistence by auto-starting the proxy at user login. While this appears intended for convenience, persistence increases risk because a local service handling robot voice traffic and file-based IPC will continue running beyond the immediate session, broadening the window for misuse or unintended exposure.

Content

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

md
## LaunchAgent (Auto-start on macOS)

Install to `~/Library/LaunchAgents/com.openclaw.vector-proxy.plist` for auto-start. See `scripts/install-launchagent.sh`.

## API Reference

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The API reference explicitly notes that cliff sensors are disabled during behavior control, but it does not provide concrete operational safeguards or restrictions for movement-related endpoints while that unsafe state is active. In a skill designed to control a physical robot, this omission can lead developers or users to issue wheel movement commands near edges, stairs, or elevated surfaces, creating a real physical safety risk to the device and surroundings.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

This finding is the same persistence mechanism: writing a plist under ~/Library/LaunchAgents is a standard macOS autostart technique. Even if intended for convenience, persistence in a robot-control proxy means the service may remain available beyond the user's immediate session and can facilitate unauthorized continued control if another weakness exists.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 7)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
NODE_PATH=$(which node)
PLIST_PATH="$HOME/Library/LaunchAgents/com.openclaw.vector-proxy.plist"

cat > "$PLIST_PATH" << EOF
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

This finding is the same persistence mechanism: writing a plist under ~/Library/LaunchAgents is a standard macOS autostart technique. Even if intended for convenience, persistence in a robot-control proxy means the service may remain available beyond the user's immediate session and can facilitate unauthorized continued control if another weakness exists.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 7)May include surrounding context.

sh
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
NODE_PATH=$(which node)
PLIST_PATH="$HOME/Library/LaunchAgents/com.openclaw.vector-proxy.plist"

cat > "$PLIST_PATH" << EOF
<?xml version="1.0" encoding="UTF-8"?>

Session Persistence

Medium
Category
Rogue Agent
Confidence
94% confidence
Finding

The here-document begins constructing a LaunchAgent plist, which is the artifact used to achieve session persistence on macOS. Persistence is security-relevant because it ensures recurring execution of the proxy process, making accidental exposure or later compromise more durable in a skill that interfaces with a physical robot and its sensors.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 9)May include surrounding context.

sh
NODE_PATH=$(which node)
PLIST_PATH="$HOME/Library/LaunchAgents/com.openclaw.vector-proxy.plist"

cat > "$PLIST_PATH" << EOF
<?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">

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

This is another duplicate hit on the same plist creation logic and reflects the same persistence concern. Autostarting a robot proxy at every login is not inherently malicious, but it is a genuine persistence mechanism with security implications if the proxy exposes control, camera, or audio interfaces.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 11)May include surrounding context.

sh
cat > "$PLIST_PATH" << EOF
<?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>

Session Persistence

Medium
Category
Rogue Agent
Confidence
93% confidence
Finding

This is another duplicate hit on the same plist creation logic and reflects the same persistence concern. Autostarting a robot proxy at every login is not inherently malicious, but it is a genuine persistence mechanism with security implications if the proxy exposes control, camera, or audio interfaces.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 11)May include surrounding context.

sh
cat > "$PLIST_PATH" << EOF
<?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>

Session Persistence

Medium
Category
Rogue Agent
Confidence
92% confidence
Finding

The LaunchAgent label identifies the persistent service that will be registered for recurring execution. In this skill's context, the danger is elevated compared with a simple desktop utility because the background process supports interaction with a physical robot and potentially its camera, so continued availability can have privacy and safety implications.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 12)May include surrounding context.

sh
cat > "$PLIST_PATH" << EOF
<?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>com.openclaw.vector-proxy</string>

Session Persistence

Medium
Category
Rogue Agent
Confidence
91% confidence
Finding

The completion of the plist file finalizes the persistence artifact that will later be loaded into launchd. Although this is part of the same overall mechanism, it still represents a true persistence-related concern because it creates a durable startup configuration for a robot-control proxy.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 32)May include surrounding context.

sh
<key>StandardErrorPath</key>
    <string>$SCRIPT_DIR/proxy-error.log</string>
</dict>
</plist>
EOF

launchctl load "$PLIST_PATH"

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

This duplicate finding points to the same launchctl load-based registration of the generated plist, which is a genuine session persistence mechanism. The skill context makes it somewhat more dangerous because the persisted service is not just a helper app; it supports a robot proxy that may expose control and sensor-related capabilities over time.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 35)May include surrounding context.

sh
</plist>
EOF

launchctl load "$PLIST_PATH"
echo "LaunchAgent installed and started"
echo "Proxy will auto-start on boot"

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

This duplicate finding points to the same launchctl load-based registration of the generated plist, which is a genuine session persistence mechanism. The skill context makes it somewhat more dangerous because the persisted service is not just a helper app; it supports a robot proxy that may expose control and sensor-related capabilities over time.

Content

Scanner excerpt · scripts/install-launchagent.sh (reported line 35)May include surrounding context.

sh
</plist>
EOF

launchctl load "$PLIST_PATH"
echo "LaunchAgent installed and started"
echo "Proxy will auto-start on boot"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The proxy writes full user chat content and raw request data to local files on disk, which can expose sensitive prompts, credentials, or personal data to other local users, processes, backups, or forensic recovery. In this robot-control context, prompts may also include camera/physical-environment details or commands tied to a physical device, increasing privacy sensitivity.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script silently captures the robot's camera stream, extracts a JPEG frame, and writes it to disk without any user notification, consent check, or visibility into where the image is stored. In the context of a physical robot with a live camera, this creates a real privacy risk because a caller can covertly collect images of the surrounding environment and persist them for later access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

Documenting a voice command logs endpoint without any privacy warning normalizes access to potentially sensitive spoken content and metadata without clarifying retention, access control, or user consent expectations. In the context of a robot that captures voice interactions in a home or office environment, exposed or casually used logs can reveal private conversations, commands, or behavioral patterns.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

Logging the user's message content to the console can leak sensitive information into terminal history, process supervisors, container logs, or centralized logging systems without the user's awareness. Although console exposure is usually narrower than file persistence, it still creates unnecessary disclosure risk for chat content.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.