Back to skill

Security audit

SmartEye - Agent的眼睛

Security checks for vulnerabilities and agentic risk

Overview

SmartEye discloses that it views and controls cameras, but its handling of camera credentials, saved snapshots, and broad activation phrases needs review before installation.

Install only if you intend to let the agent access private camera feeds and PTZ controls. Use dedicated low-privilege camera accounts, restrict the camera config file permissions, avoid shared machines for VLC live viewing, review or disable broad triggers for multi-camera capture, and periodically delete saved snapshots.

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

Warning
Location
src/config.py:22
Finding
Camera credential file is created without enforced restrictive permissions<![CDATA[ ## Vulnerability Details **File Location**: `src/config.py:22-27` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code ```python def _ensure_file(): """首次运行时将捆绑模板复制到用户配置路径。""" if not DEVICE_FILE.exists(): DEVICE_FILE.parent.mkdir(parents=True, exist_ok=True) if BUNDLED_TEMPLATE.exists(): shutil.copy(BUNDLED_TEMPLATE, DEVICE_FILE) ``` ### Technical Analysis The copied `camera-devices.json` file is explicitly intended to contain camera usernames and passwords. However, `_ensure_file()` does not set restrictive permissions on either the workspace directory or the resulting credential file. `Path.mkdir()` and `shutil.copy()` rely on the process umask and source-file permissions. A commonly packaged template may be readable by all local users, and `shutil.copy()` preserves its permission mode. The documentation advises users to protect the file, but documentation alone does not enforce the confidentiality of the credentials. Exploitation requires local filesystem access and depends on the effective permissions and operating-system access controls. This is not a remote credential theft vulnerability by itself. ### Attack Path 1. SmartEye runs for the first time and copies the bundled template to `~/.openclaw/workspace/camera-devices.json`. 2. The user replaces the placeholder values with real camera credentials. 3. The copied file retains permissive permissions, or the process umask allows local users to read it. 4. Another local account or compromised process reads the configuration file. 5. The attacker reuses the exposed credentials to connect to the RTSP service or other camera management interfaces. ### Impact Assessment A successful attacker may obtain: - Camera usernames and passwords. - Access to private live video streams and snapshots. - PTZ control privileges available to the compromised camera account. - Access to other camera interfaces if the sa ...[truncated 228 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the workspace directory with owner-only permissions: ```python DEVICE_FILE.parent.mkdir(parents=True, exist_ok=True, mode=0o700) DEVICE_FILE.parent.chmod(0o700) ``` 2. After copying the configuration, explicitly set mode `0600` on POSIX systems: ```python shutil.copyfile(BUNDLED_TEMPLATE, DEVICE_FILE) DEVICE_FILE.chmod(0o600) ``` 3. Before loading the file, inspect its permissions and warn or refuse to load real credentials when group or world access is enabled. 4. Use operating-system-specific access-control APIs on Windows rather than relying exclusively on POSIX mode bits. 5. Prefer a system keyring or secret manager for passwords. Keep only non-sensitive device metadata in the JSON file. 6. Recommend dedicated, least-privileged camera accounts instead of administrator accounts, and discourage credential reuse. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/protocol/brands/tplink.py:104
Finding
Camera credentials are exposed through VLC process arguments<![CDATA[ ## Vulnerability Details **File Locations**: - `src/protocol/brands/tplink.py:104-121` - `src/protocol/brands/huawei.py:101-120` - `src/protocol/base.py:166-178` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code TP-Link constructs a credential-bearing RTSP URL and passes it to VLC: ```python def get_rtsp_url(self, stream: str = "main") -> str: """返回 TP-Link RTSP URL。密码中特殊字符自动 URL 编码。""" import urllib.parse user_enc = urllib.parse.quote(self.user, safe="") pass_enc = urllib.parse.quote(self.pass_, safe="") rtsp_port = self.config.get("rtsp_port", 554) rtsp_path = self.config.get("rtsp_path", "stream1") return ( f"rtsp://{user_enc}:{pass_enc}" f"@{self.host}:{rtsp_port}/{rtsp_path}" ) def open_vlc(self) -> bool: """调用 VLC 打开实时流(需配置 vlc_path)。""" import subprocess vlc = self.config.get("vlc_path") if not vlc: return False rtsp = self.get_rtsp_url() try: subprocess.Popen([vlc, rtsp], start_new_session=True) return True except Exception: return False ``` Huawei uses the same credential-bearing URL pattern: ```python def get_rtsp_url(self, stream: str = "main") -> str: """返回华为 RTSP URL。""" import urllib.parse user_enc = urllib.parse.quote(self.user, safe="") pass_enc = urllib.parse.quote(self.pass_, safe="") rtsp_port = self.config.get("rtsp_port", 554) base_path = self.config.get("rtsp_path", "LiveMedia/ch1/Media1") if stream == "sub": base_path = base_path.replace("Media1", "Media2") return f"rtsp://{user_enc}:{pass_enc}@{self.host}:{rtsp_port}/{base_path}" def open_vlc(self) -> bool: """调用 VLC 打开实时流(需配置 vlc_path)。""" import subprocess vlc = self.config.get("vlc_path") if not vlc: return False rtsp = self.get_rtsp_url() try: subprocess.Popen([vlc, rtsp], start_new_session=True) return True except ...[truncated 2619 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Avoid putting credentials in VLC command-line arguments. Use a supported VLC authentication mechanism that supplies credentials through a protected configuration channel or interactive credential interface. 2. If VLC cannot securely receive RTSP credentials, use a local intermediary that authenticates to the camera and exposes a short-lived local stream URL without embedded long-term credentials. 3. Use short-lived tokens where supported instead of reusable account passwords. 4. Provision a dedicated read-only streaming account for live viewing. Do not reuse an administrator or PTZ-control account for RTSP access. 5. Ensure error messages and logs never include the full RTSP URL. Implement a redaction function that transforms it into a form such as: ```text rtsp://***:***@camera-host:554/stream1 ``` 6. Document that third-party player processes may expose their launch arguments, and disable the VLC integration by default until a protected credential path is configured. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (37)

Vague Triggers

Medium
Confidence
89% confidence
Finding
The view and control triggers include short, generic actions like '看看', '分析', '截图', and PTZ commands that may be matched without strong scoping. This increases the chance that ordinary conversation or ambiguous commands will cause camera snapshots, stream access, or physical PTZ movement, which affects both privacy and safety in the monitored environment.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The multi-camera search triggers such as '帮我找', '在哪里', and '有没有' are very broad and overlap with normal conversation. In a voice- or chat-driven agent, this can cause unintended activation that captures images from all configured cameras and sends them for analysis, creating privacy exposure and potentially opening live surveillance actions without clear user intent.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The configuration marks pan, tilt, and zoom as "supported": true, but the inline notes explicitly say the fixed-lens camera cannot physically rotate or change zoom. This is an active contradiction between the documented intent in the notes and the declared operational capability in the same config.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This code file contains user-facing natural-language guidance entirely in Chinese, including safety instructions, but does not indicate that the skill is region-specific or provide any opt-in/alternative language. Per the policy, forcing a specific language without user choice is a natural-language policy violation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return False
        rtsp = self.get_rtsp_url()
        try:
            subprocess.Popen([vlc_path, rtsp], start_new_session=True)
            return True
        except Exception:
            return False
Confidence
82% confidence
Finding
The code launches an external executable using a path taken directly from configuration, which can cause arbitrary local program execution if that configuration is tampered with. Although subprocess.Popen is invoked without shell=True, reducing shell injection risk, the danger remains because an attacker who can modify vlc_path can make the application execute any binary under the agent's privileges.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The dispatcher and default stop implementation route to ONVIF device-control operations such as continuous movement, absolute movement, and stop, including a direct self.onvif.stop(self.profile_token) call at L84. These actions can affect physical device behavior, but the file contains no confirmation prompt, user-facing logging, or explicit warning text describing that commands will be sent to a camera over the network.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The module docstring states '鉴权关闭,无密码' and emphasizes no hardcoded credentials, which conveys that this integration operates without authentication. However, get_rtsp_url URL-encodes self.user and self.pass_ and embeds them into an RTSP URL, indicating credential-based access is used in practice for streaming.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return False
        rtsp = self.get_rtsp_url()
        try:
            subprocess.Popen([vlc, rtsp], start_new_session=True)
            return True
        except Exception:
            return False
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The SSL context disables hostname checking and certificate validation, which weakens transport security for requests sent by this module. The file does not include any warning, comment, or user disclosure explaining this safety-impacting behavior or its risks.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code performs HTTP requests to a device control endpoint and is used by movement functions such as ContinuousMove, AbsoluteMove, and Stop, which can directly affect physical device behavior. Although there is a brief module comment about workspace files, there is no confirmation prompt, logging, or user-facing warning in this file that camera-control commands will be transmitted over the network.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This code exposes movement operations for a network-connected camera, including absolute move, continuous move, stop, and home positioning, but provides no user-facing disclosure, confirmation, or warning that these calls will physically move the device. Physical control of surveillance equipment can affect privacy and system behavior, so some visible warning is expected when such actions are invoked.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The function constructs and returns an RTSP URL containing username and password in the authority component. Even with URL encoding, embedding secrets directly in a reusable string increases the chance of credential leakage through logs, exceptions, telemetry, UI display, clipboard use, or downstream storage by callers.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
Adding an external process-launch capability to a PTZ control module increases attack surface and crosses from device control into local command execution. In this context, the feature is not necessary for core PTZ behavior and becomes more dangerous because it can be triggered in environments where the agent has desktop or host access, potentially exposing camera credentials and enabling abuse of local execution paths.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code passes a credential-bearing RTSP URL to an external VLC process without any disclosure or containment. That creates additional leakage paths because command-line arguments may be visible to local process inspection tools, crash reports, desktop integration, or player logs, exposing camera credentials beyond the current process.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return False
        rtsp = self.get_rtsp_url()
        try:
            subprocess.Popen([vlc, rtsp], start_new_session=True)
            return True
        except Exception:
            return False
Confidence
88% confidence
Finding
The code launches an external executable using a path taken from configuration, which creates a trust boundary issue: if an attacker can influence `vlc_path`, they can cause arbitrary local program execution under the agent's privileges. Although `subprocess.Popen` is invoked without a shell and thus avoids classic shell injection, it still executes whatever binary path is supplied and passes a credential-bearing RTSP URL to that process.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code sends SOAP requests over the network to ONVIF endpoints and injects WS-UsernameToken authentication derived from the provided credentials. Although the module docstrings describe functionality, there is no confirmation prompt, user-facing log, or explicit warning that credentials and camera-control commands will be transmitted to a remote device.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The code advertises WS-Security header injection, computes a nonce and password digest, and then does nothing with them because `_add_wsse_header` ends with `pass`. As a result, requests are sent without the expected authentication header, which can cause unauthenticated PTZ/media operations, fallback to weaker behavior by integrators, or deployment of a client that operators wrongly believe is authenticated.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
`_ptz_envelope` claims to construct a SOAP envelope with WSSE authentication, but emits `<soap-env:Header/>` with no security content. In this context, the skill controls cameras via ONVIF PTZ, so a false sense of authentication is especially risky because sensitive device-control traffic may be issued assuming it is protected when it is not.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill can launch a live camera stream in VLC from a simple natural-language command without any confirmation, safety warning, or access-control step visible here. In the context of surveillance devices, this can expose real-time private footage to an operator or local session unexpectedly, making the privacy impact more serious than a generic media-open action.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill captures screenshots from all configured cameras and saves them to disk, then returns file paths for later analysis, without any consent check, retention policy, or user-facing privacy notice in this code path. In a camera-control skill, silent persistence of images increases privacy risk because sensitive scenes may be recorded and left on disk for unintended access or later misuse.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The script's title, status messages, and test inputs are all hard-coded in Chinese, indicating a fixed language/locale experience. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not present here.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The natural-language warning comment is written only in Chinese, which imposes a language choice on readers of this configuration without offering an alternative or documenting a locale-specific scope. Under the stated policy, language-specific instructions should be opt-in or clearly justified.

Unverifiable Dependency: opencv-python has 16 known advisory(ies) (CVE-2017-12864 (Integer Overflow or Wraparound in OpenCV); CVE-2017-12598 (Out-of-bounds Read in OpenCV ); CVE-2019-14493 (NULL Pointer Dereference in OpenCV.) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The dependency specification uses a broad lower-bound version (opencv-python>=4.8.0) rather than pinning to a known-safe release, so installations may resolve to different versions across environments and could include vulnerable releases if advisories affect allowed versions. Because this skill interfaces with camera/image processing, it may ingest untrusted image or video data, which increases the practical relevance of OpenCV parsing and memory-safety CVEs.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The natural-language documentation includes Chinese instructions and operational text but does not indicate that the user can choose another language or that the package is intentionally region-specific. This can violate a language/locale policy when a skill implicitly forces one language without opt-in.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The module docstring and subsequent inline documentation are written entirely in Chinese, and there is no indication that language choice is optional or that the skill is intentionally limited to a Chinese-speaking context. Under the policy rules, forcing a specific language without user opt-in is a natural-language policy concern.

Static analysis

No suspicious patterns detected.