Back to skill

Security audit

图片视频生成

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly fits its media-generation purpose, but it handles credentials, background watchers, and session data in ways that need careful review before installation.

Install only if you trust the easyclaw.bar relay and are comfortable with the skill uploading prompts/media, using OpenClaw credentials, creating cron watchers, and writing completion messages into sessions. Prefer waiting for a version that enforces HTTPS, avoids secrets in commands and URLs, scopes notifications to an explicit current-session token, and avoids direct transcript mutation.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
Findings (6)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/client.py:13
Finding

API credentials and user content are transmitted over cleartext HTTP

Content
View full analysis
Remediation
View remediation

T06 · System Persistence

Error
Location
scripts/schedule_task_watch.py:267
Finding

Platform and messaging credentials are persisted and printed in cron commands

Content
View full analysis
list[str]: args: list[str] = [] base_url = ( os.environ.get("EASYCLAW_PLATFORM_BASE_URL", "").strip() or os.environ.get("CHANJING_PLATFORM_BASE_URL", "").strip() ) platform_token = ( os.environ.get("EASYCLAW_PLATFORM_API_TOKEN", "").strip() or os.environ.get("CHANJING_PLATFORM_API_TOKEN", "").strip() ) api_key = ( os.environ.get("EASYCLAW_PLATFORM_API_KEY", "").strip() or os.environ.get("CHANJING_PLATFORM_API_KEY", "").strip() ) api_secret = ( os.environ.get("EASYCLAW_PLATFORM_API_SECRET", "").strip() or os.environ.get("CHANJING_PLATFORM_API_SECRET", "").strip() ) if base_url: args.extend(["--base-url", base_url]) if platform_token: args.extend(["--api-token", platform_token]) return args if api_key and api_secret: args.extend(["--api-key", api_key, "--api-secret", api_secret]) return args ``` ```python if channel_notification and channel_notification.get("mode") == "clawx-im-reply": args.extend(["--notify-clawx-event-id", str(channel_notification["event_id"])]) args.extend(["--notify-clawx-server-url", str(channel_notification["server_url"])]) args.extend(["--notify-clawx-device-id", str(channel_notification["device_id"])]) args.extend(["--notify-clawx-device-token", str(channel_notification["device_token"])]) if channel_notification and channel_notification.get("mode") == "easyclaw-reply": args.extend(["--notify-easyclaw-server-url", str(channel_notification["server_url"])]) args.exte ...[truncated 3301 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/schedule_task_watch.py:294
Finding

Watcher setup reads global channel credentials and enumerates session stores across agents

Content
View full analysis
dict[str, str] | None: state_path = Path( os.environ.get("OPENCLAW_SESSION_STATE_PATH", "").strip() or DEFAULT_SESSION_STATE_PATH ) payload = _read_json_file(state_path) if isinstance(payload, dict): entries = list(payload.items()) elif isinstance(payload, list): entries = list(enumerate(payload)) else: return None ... latest = max(candidates, key=lambda item: int(item.get("updated_at") or 0)) ``` ```python def _load_easyclaw_config() -> dict | None: payload = _read_json_file(DEFAULT_OPENCLAW_CONFIG_PATH) if not isinstance(payload, dict): return None channels = payload.get("channels") if not isinstance(channels, dict): return None easyclaw = channels.get("easyclaw") if not isinstance(easyclaw, dict): return None server_url = str(easyclaw.get("serverUrl") or "").strip() device_id = str(easyclaw.get("deviceId") or "").strip() device_token = str(easyclaw.get("deviceToken") or "").strip() ``` ```python def _iter_session_store_paths() -> list[Path]: configured_path = Path( os.environ.get("OPENCLAW_SESSION_STATE_PATH", "").strip() or DEFAULT_SESSION_STATE_PATH ) candidates = [configured_path] agents_dir = ( configured_path.parent.parent if configured_path.parent.parent.name == "agents" else Path.home() / ".openclaw" / "agents" ) try: for child in agents_dir.iterdir(): candidate = child / "sessions" / "sessions.json" if candidate.exists(): candidates.append(candidate) except OSError: ...[truncated 2329 chars]
Remediation
View remediation

T02 · Agent Memory Poisoning

Error
Location
scripts/cron_watch_task.py:200
Finding

Watcher directly injects assistant messages into persistent conversation state

Content
View full analysis
None: transcript_path = Path(session_file) if not transcript_path.exists(): raise RuntimeError(f"Session transcript not found: {transcript_path}") transcript_path.parent.mkdir(parents=True, exist_ok=True) try: existing_lines = transcript_path.read_text(encoding="utf-8").splitlines() except OSError as exc: raise RuntimeError(f"Failed to read session transcript: {exc}") from exc parent_id = None for line in reversed(existing_lines[-200:]): try: payload = json.loads(line) except json.JSONDecodeError: continue if payload.get("type") != "message": continue message_id = str(payload.get("id") or "").strip() if message_id: parent_id = message_id break now = datetime.now(timezone.utc) transcript_entry = { "type": "message", "id": uuid4().hex[:8], "parentId": parent_id, "timestamp": now.isoformat(timespec="milliseconds").replace("+00:00", "Z"), "message": { "role": "assistant", "content": [{"type": "text", "text": content}], "timestamp": int(now.timestamp() * 1000), }, } try: with transcript_path.open("a", encoding="utf-8", newline="\n") as handle: if existing_lines: handle.write("\n") handle.write(json.dumps(transcript_entry, ensure_ascii=False)) except OSError as exc: raise RuntimeError(f"Failed to append session transcript: {exc}") from exc ``` ```python entry = dict(ent ...[truncated 2370 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cron_watch_task.py:119
Finding

Messaging device tokens are exposed in URL query strings

Content
View full analysis
list[dict]: base_url = server_url.rstrip("/") url = ( f"{base_url}/api/v1/openclaw/bridge/inbound" f"?device_id={urllib.parse.quote(device_id)}" f"&device_token={urllib.parse.quote(device_token)}" f"&limit={limit}" ) request = urllib.request.Request(url, method="GET") try: with urllib.request.urlopen(request) as response: payload = _parse_json_response(response) except urllib.error.HTTPError as exc: raise RuntimeError( f"easyclaw inbound query failed with HTTP {exc.code}." ) from exc except urllib.error.URLError as exc: raise RuntimeError( f"Failed to query easyclaw inbound events: {exc}" ) from exc ``` Equivalent query construction occurs in watcher scheduling: ```python query = urllib.parse.urlencode( { "device_id": device_id, "device_token": device_token, "limit": str(limit), } ) request = urllib.request.Request(f"{url}?{query}", method="GET") ``` ### Technical Analysis The messaging-device token is used as a query parameter. Query strings are routinely recorded by reverse proxies, application servers, network-security products, tracing systems, monitoring agents, and support diagnostics. They may also be exposed in exception telemetry or command output. The server URL comes from OpenClaw configuration and is not checked to ensure HTTPS. URL encoding changes representation but does not provide confidentiality. Retrieving inbound events can be part of resolving a reply destination, but placing ...[truncated 825 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_video.py:296
Finding

Reference images are transmitted twice in VEO multipart requests

Content
View full analysis
2: raise ValueError("veo_3_1-fast-fl supports at most 2 images.") fields = [("model", args.model), ("prompt", prompt), ("size", args.size)] file_fields = [("input_reference[]", item) for item in all_frame_files] fields.append( ( "input_reference", json.dumps( [file_to_data_url(item) for item in all_frame_files], ensure_ascii=False, ), ) ) return { "request_kind": "multipart", "fields": fields, "file_fields": file_fields, } if len(reference_files) > 3: raise ValueError(f"{args.model} supports at most 3 reference images.") if reference_files: fields = [("model", args.model), ("prompt", prompt), ("size", args.size)] file_fields = [("input_reference[]", item) for item in reference_files] fields.append( ( "input_reference", json.dumps( [file_to_data_url(item) for item in reference_files], ensure_ascii=False, ), ) ) ``` The encoding helper is: ```python def file_to_data_url(file_path): with open(file_path, "rb") as handle: raw = handle.read() mime_type = mimetypes.guess_type(file_path)[0] or "applicat ...[truncated 1628 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (30)

Tainted flow: 'request' from os.environ.get (line 443, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The request target and credentials are derived from local configuration/environment and sent over the network without strong validation of the destination. An attacker who can influence server_url or related config can redirect device_id/device_token traffic to an attacker-controlled endpoint, causing credential exfiltration and unauthorized message access.

Content

Scanner excerpt · scripts/schedule_task_watch.py (reported line 445)May include surrounding context.

python
)
    request = urllib.request.Request(f"{url}?{query}", method="GET")
    try:
        with urllib.request.urlopen(request) as response:
            payload = _parse_json_response(response)
    except urllib.error.HTTPError:
        return []

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

声明描述的是一个面向图片/视频生成的多模型素材生产技能,但提供的代码片段仅是底层客户端组件。它负责配置 base URL、读取凭证、发送 JSON/multipart 请求、解析响应,以及对一个 veo2 自定义视频任务进行轮询获取状态。虽然其中出现 veo2 相关路径,可能是某类视频生成任务的配套接口,但该代码本身没有展示生成图片/视频的具体调用,也没有体现 banana、sora 等模型支持。因此,代码实际行为与声明的核心能力存在明显不一致:声明强调多模型媒体生成,代码体现的是平台通信和任务查询基础设施。

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared description emphasizes media generation using image/video models. This code chunk does not generate images or videos directly. Its primary function is operational orchestration after a task has been submitted: checking task completion status, constructing completion/failure messages, storing notification state on disk, resolving inbound event IDs, replying through EasyClaw/ClawX bridge APIs, appending notifications to session files, and removing scheduled watcher jobs. While it is related to VEO-generated content workflows, the actual behavior is a background task monitor/notification component, which is a materially different capability than the declared media-generation purpose.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The description claims the skill can invoke Banana, Sora, and Veo models to generate image/video assets. However, the supplied code does not perform generation at all; it only retrieves the result of an already-created task, and the endpoint shown is specifically for Veo video fetches. This is a materially different primary purpose from media generation, so the description does not accurately represent the code chunk.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

声明描述的核心能力是“调用多种模型生成图片/视频内容”。但代码中没有任何图片或视频生成模型调用逻辑,也没有 banana、sora、veo 推理请求或媒体生产处理。相反,代码的主要用途是调度一个后台 watcher:构造 OpenClaw cron create/add/edit/remove 命令,周期性检查异步 VEO relay task,并根据本地 session/config 和远程事件信息,将结果通知到会话文件、ClawX IM 或 easyclaw。其访问的资源包括本地会话状态、OpenClaw 配置、系统可执行文件定位、以及消息桥接 HTTP 接口,这些都与“生成图片视频素材”的声明不一致。因此这是明显的描述与行为不匹配。

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The multipart upload routine reads arbitrary local files from paths supplied to the client and sends their full contents to a remote server, with no safety checks, consent gate, destination validation, or restriction to trusted paths. In this skill context, which is designed for image/video generation and asset production, file upload is expected functionality, but the combination with a hard-coded default remote host over plain HTTP makes unintended exfiltration of sensitive local files significantly more dangerous.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/generate_video.py (reported line 254)May include surrounding context.

python
prompt = str(args.prompt or "").strip()
    if not prompt:
        raise ValueError("Prompt is required in builder mode. Use --prompt or switch to raw payload mode.")
    return prompt


def validate_file_paths(paths):

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/schedule_task_watch.py (reported line 163)May include surrounding context.

python
last_result: subprocess.CompletedProcess[str] | None = None
    for base_command, extra_env in _openclaw_command_candidates():
        command = [*base_command, *args]
        env = os.environ.copy()
        env.update(extra_env)
        try:
            result = subprocess.run(

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code reads session stores, session history files, and channel credentials/device tokens to infer reply targets and messaging context. For a media-generation skill, this is unnecessary access to sensitive local data and can enable surveillance of conversations, credential misuse, and covert message delivery.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This file implements cron job creation, editing, and removal plus notification routing, which is materially unrelated to the declared image/video generation purpose. Capability mismatch is dangerous because it hides persistence and background execution inside an apparently benign media skill, increasing the chance users authorize behavior they did not intend.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The file hard-codes Chinese for the display name and short description while using English for the default prompt, with no indication that users can choose their preferred language or locale. This can violate language/locale policy expectations when a skill imposes a specific language presentation without explicit opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documentation explicitly states that relay logs record user identity, request parameters, response parameters, task IDs, success status, points cost, and timestamps, but provides no user-facing notice, minimization guidance, or retention limits. In an image/video generation skill, prompts and outputs may contain sensitive personal, commercial, or copyrighted material, so undocumented broad logging increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The client sends API tokens or key/secret headers in outbound HTTP requests via request_json, but there is no confirmation prompt or user-facing warning that credentials and payload data will be transmitted to a remote platform. For code files, outbound network transmission of user or system data should have some visible disclosure unless clearly warned elsewhere or obviously implied by the skill purpose, which is not established in this file alone.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

These functions query inbound bridge events and post text replies back to external messaging endpoints using device credentials. Messaging-bridge interaction is not an obvious requirement for a skill described only as generating image/video assets, so it represents an additional capability unrelated to the declared purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script transmits device credentials and generated message content to a configurable server_url without enforcing HTTPS or validating destination trust. If a misconfigured or attacker-controlled URL is supplied, credentials and notification contents could be exposed in transit or sent to an unauthorized endpoint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

fetch_easyclaw_events places device_id and device_token into the URL query string, which can be logged by proxies, servers, browser/history tooling, and process monitors. This is especially risky because the destination is configurable and the code does not enforce HTTPS, making credential leakage more likely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

append_session_notification writes to file paths supplied via command-line arguments with no restriction that they stay within an approved session directory. An attacker who can influence these arguments could overwrite or append to arbitrary user-accessible files, corrupt session data, or tamper with local state outside the skill's intended scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This function appends assistant messages to a session transcript file and rewrites the session store metadata, but there is no confirmation, print/log statement, or explanatory comment/docstring notifying users that local conversation files will be changed. File writes affecting session history fall under the missing-warning checks for code files when they occur without visible disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes a skill for generating images and videos with models like banana, sora, and veo. This script primarily polls a task endpoint, persists watcher state, removes scheduled jobs, sends IM replies to external bridge APIs, and appends assistant messages into session transcript files, which is materially broader than direct media generation behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script reads local files, base64-encodes their contents, and includes them in outbound API requests, but it does not give the user an explicit warning at submission time that full file contents will be transmitted off-host. This creates a real privacy and data-handling risk because users may assume local files are only referenced locally rather than uploaded to a remote service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The submission paths send prompts, image/video URLs, and optionally attached file contents to a remote relay API without an explicit runtime disclosure or consent prompt. In a content-generation skill, this matters because users may provide sensitive creative assets or internal material, and the script silently forwards them to an external service.

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 · scripts/schedule_task_watch.py (reported line 166)May include surrounding context.

python
env = os.environ.copy()
        env.update(extra_env)
        try:
            result = subprocess.run(
                command,
                capture_output=True,
                text=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The code collects platform base URLs and API credentials from environment variables for background watcher authentication with no visible user notice or runtime confirmation. In a skill presented as media generation, undisclosed background credential use is risky because it expands trust boundaries and may surprise users or administrators.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The HTTP request transmits device_id and device_token as URL query parameters. Query-string secrets are more likely to be logged by servers, proxies, browser histories, and monitoring systems, increasing the chance of credential leakage and subsequent account or device impersonation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.