Back to skill

Security audit

ark-video-storyboard

Security checks for vulnerabilities and agentic risk

Overview

The skill broadly matches a video-generation workflow, but it needs review because it uses an Ark API key, downloads and stores media locally, can send files externally, and has weak safeguards around those actions.

Review this before installing. Use a limited Ark API key, avoid sensitive reference images or prompts, confirm exactly where files will be saved and sent, and do not let it auto-send media to Feishu unless the destination is explicit. The ethnicity default should be removed or overridden, and the downloader/API scripts should be hardened before use in a shared or monitored environment.

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/submit_segment.py:36
Finding
Ark API Credential Exposed Through Process Command-Line Arguments## Vulnerability Details **File Location**: `scripts/submit_segment.py:36-50` **Vulnerability Type**: Sensitive credential exposure through subprocess arguments **Risk Level**: Medium ### Vulnerable Code ```python def submit(payload: dict, api_key: str | None = None) -> dict: headers = ["-H", "Content-Type: application/json"] if api_key: headers += ["-H", f"Authorization: Bearer {api_key}"] cmd = [ "curl", "-sS", API_URL, *headers, "-d", json.dumps(payload, ensure_ascii=False), ] try: p = subprocess.run(cmd, capture_output=True, text=True, check=False) if p.returncode != 0: return {"ok": False, "error": p.stderr.strip() or "curl failed"} return json.loads(p.stdout) except Exception as e: return {"ok": False, "error": str(e)} ``` The same pattern is also present in `scripts/get_task_result.py:15-22`: ```python def get_task(task_id: str, api_key: str | None = None) -> dict: headers = ["-H", "Content-Type: application/json"] if api_key: headers += ["-H", f"Authorization: Bearer {api_key}"] cmd = ["curl", "-sS", f"{API_BASE}/{task_id}", *headers] try: p = subprocess.run(cmd, capture_output=True, text=True, check=False) ``` ### Technical Analysis Both functions interpolate the Ark API key into a curl command-line argument and then launch curl with `subprocess.run`. Although the subprocess is invoked without a shell, which prevents conventional shell metacharacter injection, the bearer credential remains present in the child process argument vector. Depending on operating-system process visibility, container configuration, endpoint monitoring, audit logging, crash reporting, or process telemetry, another local process or administrative monitoring component may capture the full curl command line. This can disclose the bearer token. Transmitting the credential t ...[truncated 1433 chars]
Remediation
## Remediation Suggestions - Replace the curl subprocess with a Python HTTPS client and place the Authorization header in the client's in-memory request structure. - Preserve normal TLS certificate and hostname verification. - If curl must be retained, supply sensitive configuration through a protected non-command-line channel, such as standard input with `curl --config -`, while ensuring the input is never logged. - Never include authorization headers in errors, debug output, task results, or telemetry. - Store configuration files containing API keys with restrictive permissions. - Fail explicitly when no credential is available rather than sending an unauthenticated request and returning an ambiguous API response. - Rotate the Ark API key after remediation if process arguments may already have been collected by monitoring systems.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_video.py:24
Finding
Unrestricted Redirected Download and Output-Path Escape## Vulnerability Details **File Location**: `scripts/download_video.py:24-56` **Vulnerability Type**: Unvalidated remote URL and path traversal in file download **Risk Level**: Medium ### Vulnerable Code ```python def download(url: str, output_path: str | None = None, create_dated_dir: bool = True, output_dir: Path | None = None) -> str: """ Download video to the specified path. Args: url: Video URL output_path: Output file path create_dated_dir: Whether to create a dated directory output_dir: Explicit output directory """ if output_dir is not None: out_dir = Path(output_dir) elif create_dated_dir: out_dir = get_output_dir() else: out_dir = Path(DEFAULT_OUTPUT_DIR) out_dir.mkdir(parents=True, exist_ok=True) if output_path: out = out_dir / output_path else: out = out_dir / "video.mp4" cmd = ["curl", "-L", "-sS", url, "-o", str(out)] p = subprocess.run(cmd, capture_output=True, text=True, check=False) if p.returncode != 0: raise RuntimeError(p.stderr.strip() or "curl download failed") return str(out) ``` ### Technical Analysis The download function accepts an arbitrary URL and invokes curl with `-L`, which follows redirects. It does not restrict the initial URL scheme or hostname and does not validate redirect destinations. A caller can therefore cause the executing host to make requests to unintended external or internal destinations. The output filename is joined directly to the selected directory without canonicalization or containment validation. A value containing `../` can escape the media directory. With `pathlib`, an absolute `output_path` also replaces the preceding base directory entirely. Consequently, the function can write or overwrite any location writable by the user running the Skill. The function also does not enforce a maximum respons ...[truncated 2312 chars]
Remediation
## Remediation Suggestions - Require HTTPS and reject all unsupported URL schemes. - Allowlist the expected Ark media-download hostnames. - Validate every redirect destination instead of following redirects without restriction. - Disable redirects unless they are required by the provider; if required, impose a small redirect limit. - Resolve the final output path with `Path.resolve()` and verify that it remains beneath the resolved approved output directory. - Reject absolute output filenames and any path containing traversal components such as `..`. - Prefer accepting only a simple filename generated internally rather than an arbitrary path. - Avoid unintended overwrites by using exclusive file creation or requiring explicit overwrite authorization. - Enable HTTP error handling, for example curl's `--fail-with-body` behavior or equivalent client-library checks. - Enforce a maximum download size, connection timeout, total timeout, and expected video content type. - Download to a temporary file inside the approved directory and atomically rename it only after validation succeeds.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The supplied code chunk implements only a narrow subset of the declared description: storyboard skeleton generation from a scene description. It does not process reference images, does not confirm anything with the user, and does not submit video generation tasks to Volcengine Ark or access external services at all. Because the declared purpose presents a broader end-to-end workflow with optional API task submission, while the actual code is just a local storyboard builder CLI, this is a meaningful description-behavior mismatch.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
This code chunk does not implement the declared storyboard/prompt-generation or Ark video task-submission workflow. Its actual purpose is simply to download a file from a URL and save it locally. That is a materially different primary behavior from the declared skill description. While downloading a generated video could be a supporting step in a larger video pipeline, the supplied code alone exposes undeclared network/file-download and local file-writing behavior and lacks the core declared capabilities such as script confirmation, storyboard creation, prompt generation, or API task submission.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Yes, there is a mismatch. The declared description presents a high-level creative workflow skill for generating storyboards/prompts and optionally submitting video-generation jobs. The supplied code chunk does not implement any of those core functions. Instead, it performs a narrower operational task: repeatedly querying an existing Ark task result and returning completion status/video URL. While polling could be a supporting part of a larger video workflow, this specific behavior is materially different from the declared primary purpose and introduces an undeclared capability/status-check function.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The code chunk only executes the backend multi-segment generation pipeline from a preexisting storyboard file. It reads storyboard JSON from disk, derives segment durations, submits segment prompts plus optional image references to the video API, polls task status, and may download resulting videos. The declared description includes upstream creative workflow behavior—generating a storyboard/prompts from a scene or images and confirming the script with the user—which is not present in this code. While optional submission to the Ark API is consistent with part of the description, the actual primary behavior here is narrower and more execution-oriented than declared. Additionally, polling and downloading are extra operational capabilities not explicitly described, though they are related to the same workflow.

Natural-Language Policy Violations

High
Confidence
98% confidence
Finding
Defaulting all human characters to East Asian unless the user specifies otherwise is an unjustified protected-attribute assumption embedded as a hard rule. This can systematically inject demographic bias into outputs, misrepresent user intent, and create discriminatory or exclusionary behavior across normal uses of the skill.

Natural-Language Policy Violations

High
Confidence
98% confidence
Finding
Defaulting all unspecified human characters to a specific ethnicity without user opt-in introduces systematic sensitive-trait bias into generated content. In a storyboard and video prompt pipeline, this can affect many scenes and outputs at scale, making the issue more dangerous because it silently shapes creative results and may exclude or misrepresent people.

Natural-Language Policy Violations

High
Confidence
99% confidence
Finding
The storyboard generator enforces an ethnicity rule for all human characters, causing every generated storyboard to inherit a race-based constraint regardless of user intent. In this skill's context, which automates prompt creation for video generation, that bias can systematically shape outputs at scale and create discriminatory, exclusionary, or policy-violating content.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill documentation instructs use of environment variables, file reads, and shell commands, but the manifest does not declare any tool scope or allowed-tools boundaries. This creates an authorization gap where a runtime may grant broader capabilities than users expect, especially because the skill reads API keys, accesses local files, and runs ffmpeg/shell operations.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill instructs sending generated files over Feishu, which extends beyond local storyboard generation into external exfiltration/messaging behavior. Even if intended for delivery, pushing local media to a messaging channel increases data-leak risk, especially when file contents, recipient/channel choice, and approval boundaries are not tightly constrained.

Session Persistence

Medium
Category
Rogue Agent
Content
- Default all human characters to **East Asian / 东方亚洲人** unless the user explicitly specifies otherwise.
- All segments must belong to the **same video**, not unrelated clips.
- Maintain continuity for character appearance, wardrobe, environment, props, lighting logic, and emotional progression.
- Write the planning fields in Chinese unless the user requests another language.
- Write the final generation prompts in English unless the user explicitly wants Chinese prompts.
- Prefer cinematic, visual, action-oriented prompts over abstract descriptions.
- Do not silently retry failed API submissions in the background without telling the user.
Confidence
71% confidence
Finding
The skill requires maintaining continuity across segments and additionally instructs writing processing details to a persistent local workflow file, which implies session-derived content may be stored and reused over time. Persistent storage of user prompts, character descriptions, and output paths can create privacy and data-retention risks if not disclosed, minimized, or access-controlled.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The reference materially expands the skill from optional remote video task submission into automatic local downloading and persistent filesystem storage. That creates side effects beyond the stated user-facing purpose, increasing the chance of unexpected local writes, storage consumption, and handling of untrusted remote content without clear user consent.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The markdown directs the skill to automatically download videos from a returned URL and write them under ~/.openclaw/media without a clear warning or explicit opt-in. Downloading remote content and persisting it locally is a meaningful side effect that can expose the user to unwanted disk usage, unsafe content handling, and hidden persistence.

Session Persistence

Medium
Category
Rogue Agent
Content
The script automatically creates the dated directory. Use `--dir` to specify a shared output directory for all segments so they end up in the same folder (important when submitting multiple segments in parallel):

```bash
# First create the shared directory (once per task)
OUTDIR=$(date +%Y%m%d%H%M%S)
mkdir -p ~/.openclaw/media/$OUTDIR
Confidence
88% confidence
Finding
Creating timestamped directories under ~/.openclaw/media for each task introduces persistent local artifacts that survive the session. That persistence may retain sensitive or unexpected media outputs on disk, especially when users may think the skill only generates prompts or submits cloud tasks.

Session Persistence

Medium
Category
Rogue Agent
Content
The script automatically creates the dated directory. Use `--dir` to specify a shared output directory for all segments so they end up in the same folder (important when submitting multiple segments in parallel):

```bash
# First create the shared directory (once per task)
OUTDIR=$(date +%YmdHMS)
mkdir -p ~/.openclaw/media/$OUTDIR
Confidence
88% confidence
Finding
Creating timestamped directories under ~/.openclaw/media for each task introduces persistent local artifacts that survive the session. That persistence may retain sensitive or unexpected media outputs on disk, especially when users may think the skill only generates prompts or submits cloud tasks.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The rule injects a sensitive demographic attribute when the user did not ask for one, causing the system to make identity decisions beyond the skill’s stated storyboard/video-generation purpose. In a generative media workflow, this can systematically bias outputs and produce unwanted or discriminatory representations across prompts and segments.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Hard-coding an ethnicity for unspecified human characters is an unjustified inference of a sensitive trait and creates biased behavior in generated prompts. Because this skill is designed to turn ideas into media generation instructions, the rule can propagate stereotype-laden defaults into every downstream storyboard and video request.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The schema hard-codes a default ethnicity for all human characters without any user request, necessity, or documented safety reason. In a storyboard-generation skill, this creates biased outputs by default and can systematically override user intent or exclude other identities, making the generation behavior discriminatory rather than neutral.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
Enforcing a default ethnicity for all human characters without opt-in is a policy and fairness flaw because it bakes a protected-attribute assumption into normal operation. In this skill context, the schema directly shapes generated creative outputs, so the bias is likely to propagate consistently across all storyboard and prompt generation.

Natural-Language Policy Violations

Medium
Confidence
98% confidence
Finding
Mandating Chinese for several planning fields without user choice is a restrictive language policy that can reduce accessibility, cause misunderstandings, and conflict with user expectations or downstream systems expecting another language. While not as severe as the ethnicity default, it is still an unjustified hard-coded constraint that may lead to exclusion or operational failure.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The output-style rule reinforces a fixed Chinese-only requirement for planning fields, further cementing a non-optional language constraint throughout the skill. In a storyboard workflow, this can create avoidable usability and interoperability issues, especially for non-Chinese-speaking users or tools processing the generated content.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The code hard-codes a demographic default, stating that all human characters are East Asian unless explicitly overridden. This introduces biased and unjustified identity assignment into generated content, which can lead to discriminatory outputs, user harm, and downstream compliance or reputational issues in a content-generation workflow.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This Python file contains natural-language comments, docstrings, and CLI help text in Chinese, including the default output directory comment and function documentation, without any indication that the skill is intended only for Chinese-speaking users. The policy requires avoiding language/locale constraints unless the user is given a choice or the restriction is explicitly justified.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
headers += ["-H", f"Authorization: Bearer {api_key}"]
    cmd = ["curl", "-sS", f"{API_BASE}/{task_id}", *headers]
    try:
        p = subprocess.run(cmd, capture_output=True, text=True, check=False)
        if p.returncode != 0:
            return {"ok": False, "error": p.stderr.strip() or "curl failed"}
        return json.loads(p.stdout)
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
headers += ["-H", f"Authorization: Bearer {api_key}"]
    cmd = ["curl", "-sS", f"{API_BASE}/{task_id}", *headers]
    try:
        p = subprocess.run(cmd, capture_output=True, text=True, check=False)
        if p.returncode != 0:
            return {"ok": False, "error": p.stderr.strip() or "curl failed"}
        return json.loads(p.stdout)
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
headers += ["-H", f"Authorization: Bearer {api_key}"]
    cmd = ["curl", "-sS", f"{API_BASE}/{task_id}", *headers]
    try:
        p = subprocess.run(cmd, capture_output=True, text=True, check=False)
        if p.returncode != 0:
            return {"ok": False, "error": p.stderr.strip() or "curl failed"}
        return json.loads(p.stdout)
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.