Back to skill

Security audit

Imou Open Device Operate

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do its stated camera-control job, but it needs review because unvalidated network endpoints can receive sensitive camera tokens and device data.

Install only if you explicitly want this agent to operate Imou/Lechange cameras. Use only the documented HTTPS Imou API base URLs, keep IMOU_APP_SECRET private, and avoid using --save on untrusted or unexpected snapshot responses until URL and file-size validation is added. Treat camera snapshots and PTZ movement as privacy-sensitive actions requiring user authorization.

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

Error
Location
scripts/imou_client.py:33
Finding

Unrestricted API Base URL Can Expose Authentication Material and Administrative Device Tokens

Content
View full analysis
str: """Build sign: MD5 of 'time:{time},nonce:{nonce},appSecret:{app_secret}' (UTF-8), 32-char lowercase hex.""" raw = f"time:{time_sec},nonce:{nonce},appSecret:{app_secret}" return hashlib.md5(raw.encode("utf-8")).hexdigest() def _request(method: str, params: dict, app_id: str, app_secret: str, base_url: str = None) -> dict: """ Send one Open API request. :param method: API method name (e.g. 'accessToken', 'setDeviceSnapEnhanced', 'controlMovePTZ'). :param params: Request params object. :param app_id: App ID. :param app_secret: App secret for sign. :param base_url: Optional base URL; uses env IMOU_BASE_URL or default if None. :return: Full response body as dict; check result.code for '0'. """ base = base_url or _get_base_url() url = f"{base.rstrip('/')}/openapi/{method}" time_sec = int(time.time()) nonce = uuid.uuid4().hex sign = _build_sign(time_sec, nonce, app_secret) body = { "system": { "ver": "1.0", "appId": app_id, "sign": sign, "time": time_sec, "nonce": nonce, }, "id": str(uuid.uuid4()), "params": params, } headers = { "Content-Type": "application/json", OPENCLAW_HEADER: OPENCLAW_HEADER_VALUE, } resp = requests.post(url, headers=headers, json=body, timeout=30) resp.raise_for_status() return resp.json() ``` The affected requests subsequently include administrative tokens and device identifiers: ```python out = _request( "setDeviceSnapEnhanced", { "token": token, ...[truncated 2833 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/device_operate.py:54
Finding

Unvalidated Snapshot URL Enables Server-Side Request Forgery and Unbounded File Downloads

Content
View full analysis
bool: """Download URL content to local file. Returns True on success.""" try: import requests headers = {"Client-Type": "OpenClaw"} resp = requests.get(url, headers=headers, timeout=60, stream=True) resp.raise_for_status() with open(path, "wb") as f: for chunk in resp.iter_content(chunk_size=8192): if chunk: f.write(chunk) return True except Exception as e: print(f"[ERROR] Download failed: {e}", file=sys.stderr) return False def cmd_snapshot(args): token = _ensure_token() r = set_device_snap_enhanced( token, args.device_serial, args.channel_id, base_url=BASE_URL or None, ) if not r.get("success"): print(f"[ERROR] Snapshot failed: {r.get('error', 'Unknown')}", file=sys.stderr) sys.exit(1) url = r.get("url", "") if not url: print("[ERROR] No snapshot URL returned.", file=sys.stderr) sys.exit(1) print(url) if getattr(args, "save", None): save_path = args.save if os.path.isdir(save_path): save_path = os.path.join(save_path, f"snap_{args.device_serial}_{args.channel_id}.jpg") if _download_url_to_file(url, save_path): print(f"[INFO] Saved to {save_path}", file=sys.stderr) ``` ### Technical Analysis When `--save` is used, the Skill trusts the snapshot URL returned by the API and passes it directly to `requests.get`. No validation is performed on the URL scheme, hostname, resolved IP address, port, or redirect destination. Because `requests` follows redirects by default for GET requests, validating only the first URL would als ...[truncated 2324 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (11)

Tainted flow: 'url' from os.environ.get (line 82, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The code downloads and saves a URL returned from an upstream API without validating the destination host, scheme, or content type. In this skill context, that creates an SSRF-style trust boundary issue: if the snapshot URL is malicious, compromised, or redirected, the tool can be induced to make arbitrary outbound requests and write attacker-controlled content to disk.

Content

Scanner excerpt · scripts/device_operate.py (reported line 59)May include surrounding context.

python
try:
        import requests
        headers = {"Client-Type": "OpenClaw"}
        resp = requests.get(url, headers=headers, timeout=60, stream=True)
        resp.raise_for_status()
        with open(path, "wb") as f:
            for chunk in resp.iter_content(chunk_size=8192):

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/imou-operate-api.md (reported line 54)May include surrounding context.

md
| Field         | Type   | Description                    |
|---------------|--------|--------------------------------|
| accessToken   | String | Admin access token            |
| expireTime    | Long   | Expiry time in **seconds**    |

Token is valid for 3 days. Request a new one when it expires or when API returns TK1002.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill requires environment secrets and network access to a cloud API, but it does not declare an explicit tool scope such as permissions or allowed-tools. That creates an authorization gap where an agent may invoke a network-capable skill without clear sandboxing or user/admin visibility into what external access and secret usage are required.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The 'Use when' text is broad and does not clearly restrict activation to deliberate device-operation requests. Because this skill can move cameras and capture images, vague routing criteria increase the chance of accidental or contextually inappropriate invocation, leading to privacy and physical-environment impacts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The search aliases include broad single-word triggers like 'imou' and '乐橙' that can match ordinary discussion of the brand rather than an intent to control devices. In an agent ecosystem, ambiguous activation can cause unintended invocation of a skill that performs real-world actions such as PTZ movement or snapshot capture.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This markdown file documents setDeviceSnapEnhanced, which returns a downloadable snapshot image URL from a device camera. The section describes the mechanics and URL validity but does not warn that invoking the endpoint captures and exposes potentially privacy-sensitive visual data.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

The client transmits sensitive control data and authentication material to a network endpoint, and the destination can be overridden via the IMOU_BASE_URL environment variable or function argument. If an attacker can influence that configuration, tokens, app identifiers, device identifiers, and signed requests could be exfiltrated to an attacker-controlled server, enabling surveillance-related abuse or credential misuse.

Content

Scanner excerpt · scripts/imou_client.py (reported line 73)May include surrounding context.

python
"Content-Type": "application/json",
        OPENCLAW_HEADER: OPENCLAW_HEADER_VALUE,
    }
    resp = requests.post(url, headers=headers, json=body, timeout=30)
    resp.raise_for_status()
    return resp.json()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

This code performs a safety-relevant remote device control action by sending a network request to move or zoom a camera, but there is no confirmation prompt, logging, print statement, or cautionary comment warning about the action's real-world effect. The function docstring describes parameters and capability requirements, but does not disclose that invoking it will actively control the device.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified as requests>=2.28.0, which is not pinned to an exact version. This makes builds non-reproducible and can cause the skill to install different releases over time, including newly introduced vulnerable or incompatible versions. In a device-operation skill that likely performs network calls to cameras or cloud APIs, dependency drift increases supply-chain and reliability risk.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.28.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +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
87% confidence
Finding

Because requests is unpinned, it is impossible to verify whether the installed version includes fixes for known advisories affecting older releases. This is more concerning in a skill used for Imou/Lechange device control and snapshot download, since HTTP client flaws could expose credentials, mishandle TLS or redirects, or leak sensitive device data depending on how the library is used.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring states "All descriptions and output in English," which is a natural-language locale constraint. The file does not offer any language choice or indicate that English is required for a justified region-specific purpose.

Content

No source excerpt is available for this finding.