Back to skill

Security audit

runninghub-video

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent RunningHub video-generation purpose, but it uploads local files, uses an API key, downloads outputs, and contains unsafe handling of remote response values that users should review before installing.

Install only if you are comfortable sending selected images and prompts to RunningHub and storing a RunningHub API key for the helper to use. Before use, confirm each local file upload and output directory, avoid sensitive images, and prefer a patched version that sanitizes downloaded filenames and blocks credential-bearing redirects.

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
scripts/runninghub_video.py:268
Finding

Server-Controlled Task Identifier Used in Output File Path

Content
View full analysis
list[Path]: results = result.get("results") or [] if not results: raise SystemExit( "Task finished but no results were returned:\n" f"{json.dumps(result, ensure_ascii=False, indent=2)}" ) out_dir.mkdir(parents=True, exist_ok=True) task_id = result.get("taskId", "runninghub-task") saved_paths: list[Path] = [] for index, item in enumerate(results): url = item.get("url") if not url: continue extension = guess_extension(item, index) destination = out_dir / f"{task_id}-{index + 1}.{extension}" download_result(str(url), destination) ``` The associated extension is also derived from remote response data without an allowlist: ```python def guess_extension(item: dict, index: int) -> str: output_type = item.get("outputType") if output_type: suffix = str(output_type).strip().lstrip(".") return suffix or "bin" parsed = urllib.parse.urlparse(str(item.get("url", ""))) name = Path(parsed.path).name suffix = Path(name).suffix.lstrip(".") if suffix: return suffix return "mp4" if index == 0 else "bin" ``` ### Technical Analysis The `taskId`, `outputType`, and result URL are supplied by the remote API. The code incorporates `taskId` and the derived extension directly into a local path without rejecting path separators, `..` components, control characters, or other unsafe filename content. The destination is not resolved and checked against the intended output directory before `download_result()` opens it with `"wb"`. A traversal-bearing `taskId`, such as `../../target`, can therefore make the resulting path resolve outside `out_dir`. Exploit ...[truncated 1493 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/runninghub_video.py:70
Finding

Bearer API Key May Be Forwarded Across Redirect Origins

Content
View full analysis
dict: request_headers = {"Accept": "application/json"} if headers: request_headers.update(headers) request_data = data if payload is not None: request_data = json.dumps(payload, ensure_ascii=False).encode("utf-8") request_headers.setdefault("Content-Type", "application/json") request = urllib.request.Request(url, data=request_data, headers=request_headers, method=method) try: with urllib.request.urlopen(request, timeout=timeout) as response: raw = response.read() ``` Authenticated calls provide the sensitive header to this generic request function: ```python def submit_task(api_key: str, endpoint: str, payload: dict) -> dict: response = request_json( endpoint, method="POST", payload=payload, headers={"Authorization": f"Bearer {api_key}"}, ) if response.get("errorMessage") and not response.get("taskId"): raise SystemExit(json.dumps(response, ensure_ascii=False, indent=2)) return response def query_task(api_key: str, task_id: str) -> dict: return request_json( QUERY_ENDPOINT, method="POST", payload={"taskId": task_id}, headers={"Authorization": f"Bearer {api_key}"}, ) ``` ### Technical Analysis The helper correctly sends the API key to hardcoded HTTPS RunningHub endpoints, which is necessary for the declared functionality. However, `urllib.request.urlopen()` uses automatic redirect handling, while the code does not validate the destination origin or explic ...[truncated 1683 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises and operationalizes network access, local file handling, and likely environment-based API key use, but the manifest does not declare any tool scope or permissions boundary. That omission weakens governance and user awareness, making it easier for an agent to perform file reads and external transfers without clear policy constraints or review.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The trigger description is broad enough to activate on common requests involving video generation, uploads, polling, or related model names, which can cause the skill to run in contexts the user did not specifically intend. In this skill, accidental invocation is more dangerous because activation can lead to local file upload and automatic downloading of generated content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly instructs automatic upload of local files to a third-party endpoint and automatic download of returned media to local storage, but it does not require an explicit warning or consent checkpoint. This creates a real data exfiltration and local-write risk, especially if users provide sensitive images or if broad triggering causes the skill to act on files the user did not expect to leave the system.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The reference explicitly instructs the skill to upload local media files to a third-party RunningHub endpoint and notes that the returned URLs are reusable, but it provides no warning about privacy, consent, retention, or handling of sensitive local content. In a skill that may automatically upload user-provided local files, this omission can lead to unintended exfiltration of personal or confidential data to an external service.

Content

No source excerpt is available for this finding.