Back to skill

Security audit

An OpenClaw skill for AI-powered multimedia generation (image, video, audio, 3D) via 170+ RunningHub API endpoints — zero dependencies, pure Python.

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its RunningHub media-generation purpose, but it handles paid API keys and uploaded media too loosely, so users should review it before installing.

Review before installing. Do not paste a RunningHub API key into chat; prefer a protected secret store or tightly scoped environment variable, rotate any key previously shared, monitor billing, avoid uploading sensitive media unless you consent to external processing, and use voice cloning only with clear permission from the voice owner.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/runninghub_app.py:100
Finding
RunningHub API Key Exposure Through Chat, Command-Line Arguments, URL Query Strings, and Plaintext Configuration<![CDATA[ ## Vulnerability Details **File Location**: - `references/api-key-setup.md:12-27` - `scripts/runninghub_app.py:61-70` - `scripts/runninghub_app.py:100-102` - `scripts/runninghub_app.py:156-167` - `scripts/runninghub.py:156-165` - `scripts/runninghub.py:242-247` - `scripts/runninghub.py:361-365` **Vulnerability Type**: Sensitive credential exposure caused by insecure secret collection, storage, and transmission practices **Risk Level**: High ### Vulnerable Code The setup instructions encourage users to provide an API key through an ordinary chat channel and interpolate it directly into a command that writes plaintext configuration: ```markdown - `"no_key"` → Guide: 1) Register at runninghub.cn 2) Create Key 3) Recharge 4) Send Key to me ## Save Key When user sends a key, verify with `--check --api-key THE_KEY`. If valid, save it: ```bash python3 -c " import json, pathlib p = pathlib.Path.home() / '.openclaw' / 'openclaw.json' p.parent.mkdir(exist_ok=True) cfg = json.loads(p.read_text()) if p.exists() else {} cfg.setdefault('skills', {}).setdefault('entries', {}).setdefault('runninghub', {})['apiKey'] = 'THE_KEY' p.write_text(json.dumps(cfg, indent=2)) " ``` ``` The AI Application client places the API key in curl process arguments as multipart form data: ```python def curl_upload(url: str, api_key: str, file_path: str, timeout: int = 120) -> subprocess.CompletedProcess: cmd = [ "curl", "-s", "-S", "--fail-with-body", "-X", "POST", url, "--max-time", str(timeout), "-H", f"Host: {API_HOST.split('//')[1]}", "-F", f"apiKey={api_key}", "-F", "fileType=input", "-F", f"file=@{file_path}", ] return subprocess.run(cmd, capture_output=True, text=True) ``` It also includes the key in a GET query string: ```python def get_node_info(api_key: str, webapp_id: str) -> list[dict]: url = f"{API_HOST}{NODE_INFO_PATH}?apiKey={api_key}&webappId={webapp_id}" result = curl_get(url) resp = _parse ...[truncated 5900 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Do not request API keys in ordinary chat** - Replace the instruction to “send the key” with a dedicated secret-entry or credential-management workflow. - Ensure secrets are excluded from conversation history, telemetry, and model context wherever the host platform supports secret inputs. - Instruct users who previously sent a key in chat to revoke and rotate it. 2. **Remove command-line secret arguments** - Deprecate `--api-key` for routine use because command arguments may be observable. - Resolve the key from a protected secret store or narrowly scoped environment variable. - Avoid constructing curl arguments containing bearer headers or secret multipart values. - Prefer an in-process HTTPS client where headers are never placed in a child process argument vector. If curl must be retained, pass sensitive configuration through protected standard input or a temporary config file with mode `0600`, then delete it promptly. 3. **Never put credentials in URLs** - Replace: ```python f"{API_HOST}{NODE_INFO_PATH}?apiKey={api_key}&webappId={webapp_id}" ``` with an authenticated request using an `Authorization: Bearer` header, provided the RunningHub API supports it. - If the upstream API requires an `apiKey` parameter, use a POST body rather than a GET query and request that the provider add header-based authentication. - Configure all relevant proxies and application logs to redact `apiKey`, `Authorization`, and similar sensitive fields. 4. **Harden local storage** - Use the platform's native encrypted secret store instead of storing the key in `openclaw.json`. - If file storage is unavoidable, create both the directory and file with restrictive permissions and validate them before reading: ```python p.parent.mkdir(mode=0o700, parents=True, exist_ok=True) fd = os.open(p, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) ``` - Reject insecure ownership or ...[truncated 996 chars]
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (32)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The description claims an operational skill for invoking many RunningHub endpoints and running custom AI applications. The supplied code chunk instead implements an offline helper script that builds a capabilities manifest from a registry file. It parses endpoint names to infer tasks like text-to-image or image-to-video, derives tags, filters parameter defaults, sorts endpoints, and writes output JSON. While the script references endpoint categories consistent with the declared domain, it does not itself perform the advertised generation or app-running capabilities. This is a material description-versus-behavior mismatch for the provided code chunk.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The manifest includes a voice-cloning endpoint that can synthesize speech from a short uploaded audio sample, but this high-risk biometric capability is not justified or disclosed by the stated skill purpose. Voice cloning materially raises impersonation, fraud, and consent risks, especially because it processes user-supplied audio and can reproduce a person's vocal identity.

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill declares executable capabilities that imply shell, environment, and file access but does not define any explicit tool scope such as allowed-tools or permissions. In an agent environment, this weakens least-privilege boundaries and can let the skill invoke broader local capabilities than users or reviewers would expect, increasing the blast radius if the skill is misused or later modified.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
Forcing all responses to Chinese without user opt-in can undermine user comprehension, informed consent, and safe operation, especially when handling costs, file delivery, progress notices, or sensitive error conditions. A user who cannot read Chinese may misunderstand actions being taken or miss warnings, which is a security-relevant UX flaw even if not an exploit primitive.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The manifest accepts uploaded images, audio, and video across many endpoints but does not provide a user-facing warning that this media will be sent to external model providers. That omission can cause users to unknowingly disclose sensitive or copyrighted media to third parties, especially in a skill that supports broad media analysis and transformation.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The capability manifest exposes substantial analysis and transformation features beyond the user-facing description of simple media generation, including image/video-to-text, video editing, motion control, reference-to-video, and media upscaling. This mismatch can mislead users and reviewers about what data will be processed and how, increasing the risk of unintended sensitive-media analysis or broader third-party data disclosure.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The default prompt explicitly instructs generation with a '地道男声京腔配音' and a specific regional speaking style. This imposes a locale-specific voice characteristic by default rather than offering it as an optional user choice.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The prompt directs the system to speak in Korean ('用韩语说') with no indication that language choice is optional. This is a natural-language policy issue because it hardcodes a language preference instead of deferring to user selection.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This default prompt again mandates a Beijing-accent male narration style for generated output. Because the manifest does not present this as an optional locale choice, it embeds a specific regional language preference by default.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The status-response examples are written as fixed Chinese replies, such as `账号就绪!余额 ¥{balance}...`, with no indication that the user can choose another language. Under SQP-3, a skill violates policy when it forces a specific language or locale without user opt-in or a clearly documented regional justification.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The instructions tell the operator to persist a sensitive API key in a plaintext local config file under the user's home directory, with no warning about filesystem exposure, local compromise, backups, or multi-user access. In the context of a skill that can invoke 170+ paid RunningHub endpoints, theft of this key could enable unauthorized API usage, account abuse, and financial loss.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The document first states that for any image generation, including image-edit/image-to-image, the assistant must show the exact 5-model menu and must not skip it. Later, it says AI-powered image editing should use a separate endpoint directly with no model menu, which directly conflicts with the earlier mandatory instruction.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The instruction says to trigger the menu whenever the user wants 'ANY image generation,' which is extremely broad and lacks clear boundary conditions. Although a later exception exists for some edit cases, the activation scope is still ambiguous enough to cause unintended invocation across many ordinary image-related requests.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
The file instructs the agent to 'Always write prompts in English' regardless of the user's language. This is a language-policy issue because it imposes a specific language without offering the user a choice or documenting an opt-in.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The example notification text is in Chinese and line L05 says to ALWAYS send this notification before starting slow tasks. Because the file provides mandatory user-facing phrasing in a specific language without mentioning user preference or locale selection, it creates a language-policy concern.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The delivery and failure-message examples are written in Chinese, and the surrounding instructions use MUST/ALWAYS language for user communication flow. This can force a specific language for end-user messages even when the user's preferred language is unknown.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The instruction to trigger the menu whenever the user wants any video is very broad and can preempt normal intent handling for nearly all video-related requests. In an agent skill, overbroad activation can hijack user flows, force unwanted tool paths, and increase the chance of inappropriate endpoint selection even when the user did not intend to invoke this specific workflow.

Natural-Language Policy Violations

Medium
Confidence
99% confidence
Finding
The skill forces prompt translation/rewriting into English without user opt-in, which can alter user meaning, style, safety constraints, or sensitive wording before it reaches the API. In generative media workflows this can degrade user control, introduce semantic drift, and cause outputs that do not reflect the user's original instructions or policy expectations.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The document mandates an exact 8-model menu and explicitly says not to invent other models, but the failure-retry section introduces an unlisted fallback model (万相2.6). This creates conflicting control flow and can cause the agent to bypass the documented selection policy, leading to inconsistent behavior, unauthorized endpoint use, or execution against models the user was never shown.

Session Persistence

Medium
Category
Rogue Agent
Content
"message": "No API key configured",
        "steps": [
            "1. Register/login at https://www.runninghub.cn",
            "2. Create API Key at https://www.runninghub.cn/enterprise-api/sharedApi",
            "3. Recharge wallet at https://www.runninghub.cn/vip-rights/4",
            "4. Send the key in chat or add to ~/.openclaw/openclaw.json: skills.entries.runninghub.apiKey",
        ],
Confidence
87% confidence
Finding
The script explicitly instructs the user to send the API key in chat or store it persistently in ~/.openclaw/openclaw.json. Encouraging secret transmission through chat and long-term plaintext local storage increases exposure risk through logs, chat retention, backup systems, or overly broad file access.

Session Persistence

Medium
Category
Rogue Agent
Content
"message": "No API key configured",
            "steps": [
                "1. Register/login at https://www.runninghub.cn",
                "2. Create API Key at https://www.runninghub.cn/enterprise-api/sharedApi",
                "3. Recharge wallet at https://www.runninghub.cn/vip-rights/4",
                "4. Send the key in chat or add to ~/.openclaw/openclaw.json: skills.entries.runninghub.apiKey",
            ],
Confidence
87% confidence
Finding
This is the same risky credential-handling guidance repeated in the account check path: it tells users to send the key in chat or place it in persistent config. Repetition in multiple execution paths increases the chance that users will follow the least secure option and expose their API credential.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Local media files are uploaded to a third-party service automatically when size thresholds are exceeded or force_upload is set, without an explicit warning or confirmation at the point of upload. In a skill context handling user-local files, this can lead to unintended disclosure of sensitive images, audio, or video to an external provider.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cmd = ["curl", "-s", "-S", "--fail-with-body", "-X", "POST", url,
           "-H", f"Authorization: Bearer {api_key}",
           "-F", f"file=@{file_path}", "--max-time", "120"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Upload failed: {result.stderr}", file=sys.stderr)
        sys.exit(1)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def download_file(url: str, output_path: str) -> str:
    Path(output_path).parent.mkdir(parents=True, exist_ok=True)
    cmd = ["curl", "-s", "-S", "-L", "-o", output_path, "--max-time", "300", url]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Download failed: {result.stderr}", file=sys.stderr)
        sys.exit(1)
Confidence
89% confidence
Finding
The script downloads an arbitrary URL returned by the remote RunningHub service directly to a local file via curl, with no allowlist or scheme/host validation. If the upstream service is compromised or malicious, this enables untrusted content retrieval to the local environment and could be abused for SSRF-like access from the host, unexpected large downloads, or placing attacker-controlled files at user-chosen paths.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def curl_get(url: str, timeout: int = 30) -> subprocess.CompletedProcess:
    cmd = ["curl", "-s", "-S", "--fail-with-body", "--max-time", str(timeout), url]
    return subprocess.run(cmd, capture_output=True, text=True)


def curl_post_json(url: str, payload: dict, timeout: int = 60) -> subprocess.CompletedProcess:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.