T09 · Insecure Skill Coding Practices
- Location
scripts/core/run_task.py:158- Finding
Confirmation-required actions are executed without user approval
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill’s desktop-control purpose is coherent, but it needs Review because its safeguards and headless remote-desktop setup are unsafe for a tool that can see and operate a user’s screen.
Install only in a disposable or tightly controlled environment until the VNC password/listener, confirmation enforcement, endpoint validation, screenshot logging, and installer secret handling are fixed. Do not use it on screens containing passwords, private documents, financial accounts, or authenticated business tools unless you fully trust the configured vision provider and network exposure.
scripts/core/run_task.py:158Confirmation-required actions are executed without user approval
scripts/setup/setup-linux.sh:69Headless setup exposes VNC with a predictable default password
scripts/vision/analyze.py:84Screenshots and bearer credentials can be transmitted to an unvalidated endpoint
install.sh:84Installer API-key interpolation permits Python code injection and weak secret handling
scripts/platform/screenshot.sh:22Screenshot fallback interpolates path and display values into executable Python source
scripts/setup/setup-linux.sh:39Runtime installers fetch unpinned third-party dependencies
scripts/core/run_task.py:97User-configured task limits are ignored in favor of hard-coded constants
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).
## 🔒 安全机制
- ❌ **自动拦截**:`rm -rf /`、格式化磁盘、`shutdown`、`drop database` 等
- ⚠️ **需确认**:涉及删除、sudo、支付等敏感操作
- ⏱️ **超时保护**:最长 5 分钟 / 100 步自动停止
- 📸 **操作日志**:所有截图保存到 `/tmp/screen-vision/logs/`
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).
## 🔒 安全机制
- ❌ **自动拦截**:`rm -rf /`、格式化磁盘、`shutdown`、`drop database` 等
- ⚠️ **需确认**:涉及删除、sudo、支付等敏感操作
- ⏱️ **超时保护**:最长 5 分钟 / 100 步自动停止
- 📸 **操作日志**:所有截图保存到 `/tmp/screen-vision/logs/`
The trigger is extremely broad, covering generic requests like opening apps, browsing websites, taking screenshots, and 'operate/control computer,' which overlaps with many normal user prompts. In practice this can cause the skill to activate in contexts involving sensitive desktop state, credentials, private documents, or unintended remote control, expanding attack surface and increasing the risk of unauthorized actions.
The skill states that screenshots are analyzed by an external vision API, but it does not prominently warn users that screen contents and task text may be transmitted off-device to third-party providers. Because screenshots can contain secrets, personal data, tokens, emails, or financial information, the missing disclosure materially increases privacy and data-exfiltration risk.
The screenshot command is built as a shell string and executed with os.system(), while display_id can come from CLI arguments or environment-derived configuration. This creates a command-injection surface where a crafted display value or path-containing metacharacters could execute arbitrary shell commands in the host context.
cmd = f"bash {script} {output_path}"
if display_id:
cmd = f"SV_DISPLAY={display_id} {cmd}"
ret = os.system(cmd)
return ret == 0 and os.path.exists(output_path)
Copying the entire process environment into a child process can unnecessarily expose secrets such as API keys, tokens, proxy credentials, and cloud metadata to downstream components. In a skill that orchestrates external scripts and remote APIs, broad environment propagation expands the blast radius if a child process is compromised or logs its environment.
cmd.extend(["--x2", str(action.get("x2", 0))])
cmd.extend(["--y2", str(action.get("y2", 0))])
env = os.environ.copy()
if display_id:
env["SV_DISPLAY"] = display_id
env["DISPLAY"] = display_id
The code copies screenshots using os.system() with shell interpolation. While the current paths are mostly internally constructed, using the shell for file operations is unsafe and can become exploitable if path assumptions change, symlinks are abused, or surrounding state is attacker-controlled.
# Save screenshot log
if safety_config.get("screenshot_log", True):
log_ss = os.path.join(log_dir, f"step_{action_count:03d}.png")
os.system(f"cp {ss_path} {log_ss} 2>/dev/null")
# Wait and take new screenshot
time.sleep(wait_after)
Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.
def run_cmd(cmd, display=None):
"""Run command with optional DISPLAY env."""
import os
env = os.environ.copy()
if display and get_os() == "linux":
env["DISPLAY"] = display
result = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=10)
The Python fallback is built by interpolating shell variables directly into a Python -c string, so attacker-controlled values such as OUTPUT or DISPLAY_ID can break out of the intended quoting and inject arbitrary Python code. In a skill that performs desktop automation and may run with access to a user's session, this can lead to arbitrary command execution and compromise of the local environment.
# Fallback: use Python
python3 -c "
import subprocess
subprocess.run(['DISPLAY', '$display', 'scrot', '-z', '-overwrite', '$OUTPUT'], env={'DISPLAY': '$display', 'PATH': '/usr/bin:/bin'})
" 2>/dev/null && return 0
echo "ERROR: No screenshot tool available on Linux" >&2
The script silently provisions remote desktop access by writing VNC credentials and installing executable start/stop helpers under /usr/local/bin, but gives no explicit warning that this creates a remotely reachable control plane for the machine. In a screen-control skill, this is especially dangerous because it expands from local automation to persistent remote GUI access, increasing the attack surface substantially.
The script sets a hardcoded default VNC password ('screen123') and stores its VNC-hashed form automatically, meaning every installation can share the same easily guessed credential. Because the skill is explicitly designed for desktop control, compromise of this password can grant full interactive control of the host's GUI session.
The stop script reads a PID from a predictable file in /tmp and passes it directly to 'kill' without validating ownership, file type, or whether the PID belongs to the expected websockify process. A local attacker could tamper with /tmp/sv-novnc.pid or exploit symlink/race conditions to cause termination of unintended processes run by the same user, or by root if the helper is executed with elevated privileges.
echo "Stopping screen-vision desktop..."
vncserver -kill :1 2>/dev/null
kill $(cat /tmp/sv-novnc.pid 2>/dev/null) 2>/dev/null
rm -f /tmp/sv-novnc.pid
echo "Stopped."
SCRIPT
chmod +x /usr/local/bin/sv-stop
The external API endpoint itself is expected functionality for a vision skill, but the README shows configuration for a third-party endpoint without an adjacent privacy/security warning. Given that the tool captures full-screen images, using an external provider can expose sensitive desktop content if users are not clearly informed.
{
"vision": {
"baseUrl": "https://api.siliconflow.cn/v1",
"apiKey": "YOUR_API_KEY",
"model": "Qwen/Qwen3-VL-32B"
}
The environment-variable example encourages configuring an external vision endpoint, which is normal for the product, but it still represents external transmission of potentially sensitive screenshots. In the context of a computer-control skill, this is more dangerous than ordinary API use because the captured screen may include high-value secrets from unrelated applications.
export SV_VISION_API_KEY=your_api_key
export SV_VISION_BASE_URL=https://api.siliconflow.cn/v1
export SV_VISION_MODEL=Qwen/Qwen3-VL-32B
The README promotes sending screenshots to 'all OpenAI-compatible vision APIs' but does not clearly warn that on-screen content may be transmitted to third-party providers. In a desktop-control skill, screenshots can contain passwords, messages, financial data, or proprietary information, so omission of this disclosure meaningfully increases privacy and data-handling risk.
The README states that all screenshots are saved under /tmp/screen-vision/logs/ but does not warn that these logs may retain sensitive on-screen data locally. Because this skill continuously captures the desktop, the saved images may include secrets, personal data, and enterprise information that remain accessible to other local users or later processes depending on system configuration.
The skill advertises capabilities that imply shell execution, network access, environment-variable use, and file writes, but it declares no explicit tool scope or permission boundaries. For a desktop-control skill that can take screenshots, call external APIs, and execute platform commands, the absence of declared restrictions increases the chance of overbroad invocation and unintended access to sensitive local data or system functions.
Autonomous decision-making in a screenshot-to-action loop is inherently risky for a desktop-control skill because the model can choose clicks, typing, navigation, and other actions based on imperfect visual interpretation. In this context, autonomy can lead to unintended data disclosure, destructive UI actions, or interaction with security-sensitive prompts unless tightly constrained and confirmed.
name: screen-vision
description: >
AI screen vision and desktop computer control skill for OpenClaw.
Let your AI agent see the screen, understand UI elements, and autonomously perform
mouse and keyboard operations (click, type, scroll, drag) via a screenshot-analyze-action loop.
Cross-platform: Linux (headless server with XFCE4+noVNC, or desktop), macOS (cliclick),
Windows (pyautogui). Supports any OpenAI-compatible vision API (SiliconFlow, OpenAI,
The installer accepts an API key on the command line and writes it directly into config.json, creating a plaintext credential at rest without warning, permission hardening, or preference for safer secret sources. In the context of a desktop-control skill that can access vision APIs and potentially sensitive screenshots, compromise of that key could enable unauthorized API usage, billing abuse, and exposure of screen-derived data sent through the configured provider.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| 字段 | 说明 | 示例 |
|------|------|------|
| `baseUrl` | API 地址 | `https://api.siliconflow.cn/v1` |
| `apiKey` | API 密钥 | `sk-xxx...` |
| `model` | 视觉模型名称 | `Qwen/Qwen3-VL-32B` |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| 字段 | 说明 | 示例 |
|------|------|------|
| `baseUrl` | API 地址 | `https://api.siliconflow.cn/v1` |
| `apiKey` | API 密钥 | `sk-xxx...` |
| `model` | 视觉模型名称 | `Qwen/Qwen3-VL-32B` |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| 字段 | 说明 | 示例 |
|------|------|------|
| `baseUrl` | API 地址 | `https://api.siliconflow.cn/v1` |
| `apiKey` | API 密钥 | `sk-xxx...` |
| `model` | 视觉模型名称 | `Qwen/Qwen3-VL-32B` |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| 字段 | 说明 | 示例 |
|------|------|------|
| `baseUrl` | API 地址 | `https://api.siliconflow.cn/v1` |
| `apiKey` | API 密钥 | `sk-xxx...` |
| `model` | 视觉模型名称 | `Qwen/Qwen3-VL-32B` |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| 字段 | 说明 | 示例 |
|------|------|------|
| `baseUrl` | API 地址 | `https://api.siliconflow.cn/v1` |
| `apiKey` | API 密钥 | `sk-xxx...` |
| `model` | 视觉模型名称 | `Qwen/Qwen3-VL-32B` |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
{
"vision": {
"provider": "openai",
"baseUrl": "https://api.openai.com/v1",
"apiKey": "sk-your-key",
"model": "gpt-5.4-mini" // 替换为你使用的模型
}
No suspicious patterns detected.