Back to skill

Security audit

Qwen Video (Wan)

Security checks for vulnerabilities and agentic risk

Overview

This video-generation skill is purpose-aligned, but it uses unsafe shell networking and input handling that could expose the API key or allow command execution through crafted arguments.

Review before installing. Use only with non-sensitive prompts and audio URLs, and do not use current scripts with valuable DashScope credentials until curl -k is removed, inputs are validated, JSON is built safely, and returned media URLs are constrained to expected HTTPS hosts.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/submit.sh:60
Finding
TLS Certificate Verification Disabled for Authenticated API Requests and Media Downloads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/submit.sh:60-64`, `scripts/poll.sh:44-45`, `scripts/generate.sh:76-78` **Vulnerability Type**: Improper certificate validation **Risk Level**: High ### Vulnerable Code `scripts/submit.sh:60-64`: ```bash RESP=$(curl -sS -k --location "$API_URL" \ -H 'X-DashScope-Async: enable' \ -H "Authorization: Bearer $DASHSCOPE_API_KEY" \ -H 'Content-Type: application/json' \ -d "$DATA") ``` `scripts/poll.sh:44-45`: ```bash RESP=$(curl -sS -k --location "https://dashscope.aliyuncs.com/api/v1/tasks/$TASK_ID" \ -H "Authorization: Bearer $DASHSCOPE_API_KEY") ``` `scripts/generate.sh:76-78`: ```bash # Download mkdir -p "$(dirname "$OUT")" curl -L -k -o "$OUT" "$VIDEO_URL" ``` ### Technical Analysis The `-k` option instructs `curl` to accept TLS certificates without verifying their authenticity. It is used for both authenticated DashScope API calls and the final media download. Because certificate verification is disabled, HTTPS encryption does not establish that the remote endpoint is the legitimate DashScope service. An attacker capable of intercepting network traffic, controlling a proxy, influencing DNS, or presenting a malicious certificate can impersonate the API endpoint. The authenticated requests include the DashScope bearer token in the `Authorization` header. A successful interception can therefore disclose the API key. A forged polling response can also provide an attacker-selected `video_url`, after which `generate.sh` downloads attacker-controlled content while again disabling certificate validation. ### Attack Path 1. A user invokes `submit.sh`, `poll.sh`, or `generate.sh` with `DASHSCOPE_API_KEY` set. 2. An attacker obtains a network interception position, controls a configured proxy, or redirects the DashScope hostname. 3. The attacker presents an invalid or attacker-issued TLS certificate. 4. Because `curl -k` disables certificate validation, the scripts accept the connection. 5 ...[truncated 930 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `-k` from every `curl` invocation: ```bash curl --fail-with-body --show-error --silent --location ... ``` 2. Use the operating system's trusted certificate store and fail closed when certificate validation fails. 3. If an organization uses an authorized TLS inspection proxy, install its CA certificate in the trust store or provide it explicitly with `--cacert`; do not disable all verification. 4. Validate the returned media URL before downloading it: - Require the `https` scheme. - Restrict the hostname to documented DashScope or Alibaba Cloud media domains. - Reject embedded credentials, unexpected ports, and malformed URLs. 5. Consider disabling redirects or limiting them with `--proto '=https'` and `--proto-redir '=https'`. 6. Use `--fail-with-body` so HTTP failures cannot be mistaken for valid API or media responses. 7. Rotate any API key that has already been used over untrusted networks with these scripts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/submit.sh:52
Finding
Unescaped User Input Allows JSON Request-Structure Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/submit.sh:52-58` **Vulnerability Type**: Improper construction of JSON from untrusted input **Risk Level**: Medium ### Vulnerable Code ```bash # Build JSON (avoid jq dependency) AUDIO_FIELD="" if [[ -n "$AUDIO_URL" ]]; then AUDIO_FIELD=",\"audio_url\":\"$AUDIO_URL\"" fi DATA="{\"model\":\"$MODEL\",\"input\":{\"prompt\":\"$PROMPT\"$AUDIO_FIELD},\"parameters\":{\"size\":\"$SIZE\",\"prompt_extend\":$PROMPT_EXTEND,\"duration\":$DURATION,\"shot_type\":\"$SHOT_TYPE\"}}" ``` The affected values originate from command-line arguments parsed at `scripts/submit.sh:27-38`, including `PROMPT`, `SIZE`, `DURATION`, `MODEL`, `SHOT_TYPE`, and `AUDIO_URL`. ### Technical Analysis The script constructs JSON by directly concatenating command-line values into a string. It does not JSON-escape quotation marks, backslashes, newlines, control characters, or other structural content. A prompt containing an ordinary quotation mark can already make the body invalid. More deliberately crafted input can close the current JSON string and inject additional properties or alter the structure of the request. `DURATION` is especially unsafe because it is inserted as an unquoted JSON token without checking that it is an allowed integer. Shell quoting around `"$DATA"` prevents conventional shell metacharacters in these values from becoming shell commands at this location. The confirmed issue is injection into the JSON request sent to DashScope, not direct local shell execution through `DATA`. ### Attack Path 1. An untrusted caller influences a value passed through `--prompt`, `--audio-url`, `--model`, `--size`, `--duration`, or `--shot-type`. 2. The value contains quotation marks, delimiters, or other JSON syntax designed to terminate its intended field. 3. `submit.sh` concatenates the value into `DATA` without escaping or type validation. 4. The resulting request is either malformed or contains attacker-selected JSON fields ...[truncated 676 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Build the request with a JSON-aware tool rather than string concatenation. For example: ```bash DATA=$(jq -n \ --arg model "$MODEL" \ --arg prompt "$PROMPT" \ --arg size "$SIZE" \ --arg shot_type "$SHOT_TYPE" \ --argjson prompt_extend "$PROMPT_EXTEND" \ --argjson duration "$DURATION" \ '{ model: $model, input: {prompt: $prompt}, parameters: { size: $size, prompt_extend: $prompt_extend, duration: $duration, shot_type: $shot_type } }') ``` 2. Add `audio_url` through the JSON tool only when supplied, rather than constructing an `AUDIO_FIELD` fragment. 3. Validate every structured option before creating the request: - Require `DURATION` to be a bounded decimal integer. - Allow only supported values for `MODEL`, `SIZE`, and `SHOT_TYPE`. - Require `PROMPT_EXTEND` to be exactly `true` or `false`. - Parse `AUDIO_URL` and require an allowed HTTPS URL. 4. Reject invalid values locally with a clear error instead of relying on remote API validation. 5. Add tests covering quotes, backslashes, Unicode, newlines, and control characters in prompts. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/poll.sh:71
Finding
Unvalidated Timeout Value Is Evaluated as a Bash Arithmetic Expression<![CDATA[ ## Vulnerability Details **File Location**: `scripts/poll.sh:22-27`, `scripts/poll.sh:71-77`; reachable through `scripts/generate.sh:40,72` **Vulnerability Type**: Command injection through unsafe arithmetic evaluation **Risk Level**: High ### Vulnerable Code `scripts/poll.sh:22-27` accepts the timeout without numeric validation: ```bash while [[ $# -gt 0 ]]; do case "$1" in -h|--help) usage; exit 0;; --task-id) TASK_ID=${2:-}; shift 2;; --max-wait-sec) MAX_WAIT_SEC=${2:-1200}; shift 2;; --interval-sec) INTERVAL_SEC=${2:-5}; shift 2;; ``` `scripts/poll.sh:71-77` evaluates the value in an arithmetic context: ```bash if (( ELAPSED >= MAX_WAIT_SEC )); then echo "Timeout after ${MAX_WAIT_SEC}s" >&2 echo "$RESP" >&2 exit 1 fi sleep "$INTERVAL_SEC" ``` The value can also enter this path through `scripts/generate.sh`: ```bash --max-wait-sec) MAX_WAIT_SEC=${2:-1200}; shift 2;; ``` ```bash VIDEO_URL=$(bash "$BASE_DIR/scripts/poll.sh" --task-id "$TASK_ID" --max-wait-sec "$MAX_WAIT_SEC" --interval-sec "$INTERVAL_SEC" | sed -n 's/^VIDEO_URL: //p' | tail -n 1) ``` ### Technical Analysis Bash arithmetic contexts do not merely convert arbitrary strings to integers. Variable values can be interpreted recursively as arithmetic expressions. Arithmetic parsing supports variable and array references, and array subscript processing can trigger shell expansions such as command substitution. Consequently, an attacker-controlled value supplied as `--max-wait-sec` can be interpreted as executable arithmetic syntax when this statement is reached: ```bash (( ELAPSED >= MAX_WAIT_SEC )) ``` For example, an expression shaped like an array reference with a command substitution in its subscript can cause the command substitution to execute during arithmetic evaluation. The exact payload may depend on the Bash version and variable environment, but the unsafe primitive is present because unrestricted text is passed into recursive arithmetic evaluat ...[truncated 1665 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate timeout and interval values immediately after parsing and before any arithmetic use: ```bash [[ "$MAX_WAIT_SEC" =~ ^[0-9]+$ ]] || { echo "Error: --max-wait-sec must be a non-negative integer" >&2 exit 2 } [[ "$INTERVAL_SEC" =~ ^[0-9]+$ ]] || { echo "Error: --interval-sec must be a non-negative integer" >&2 exit 2 } ``` 2. Apply reasonable upper and lower bounds, for example: ```bash (( 1 <= MAX_WAIT_SEC && MAX_WAIT_SEC <= 3600 )) || exit 2 (( 1 <= INTERVAL_SEC && INTERVAL_SEC <= 300 )) || exit 2 ``` 3. To avoid interpreting a validated value with leading-zero semantics, normalize it as base 10: ```bash MAX_WAIT_SEC=$((10#$MAX_WAIT_SEC)) INTERVAL_SEC=$((10#$INTERVAL_SEC)) ``` Handle zero separately if the supported Bash version rejects `10#` without following digits. 4. Perform the same validation in `generate.sh` before forwarding values to `poll.sh`, while retaining validation in `poll.sh` as the security boundary. 5. Add regression tests using nonnumeric strings, arithmetic expressions, array references, command-substitution patterns, negative values, and excessively large values. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The code does match part of the declared purpose: it submits an async DashScope Wan video-generation request using a text prompt. However, the description says the skill should also poll status and download the MP4 locally, which this code does not do. Its behavior ends after submission and task_id extraction. Additionally, the script accepts an optional audio_url parameter, extending functionality beyond a pure text-to-video description. Because key declared lifecycle steps (polling and downloading) are missing, the description does not accurately represent the supplied code chunk.

Missing User Warnings

High
Confidence
99% confidence
Finding
Using `curl -L -k` silently bypasses certificate verification without warning the user, defeating HTTPS protections and making network interception or content substitution feasible. Because this skill's purpose is to fetch and save generated media from an external service, transport integrity is security-relevant and disabling it is unjustified by the stated functionality.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
# Download
mkdir -p "$(dirname "$OUT")"
curl -L -k -o "$OUT" "$VIDEO_URL"

FULL=$(python3 -c 'import os,sys; print(os.path.abspath(sys.argv[1]))' "$OUT")
echo "MEDIA: $FULL"
Confidence
97% confidence
Finding
The `curl -L -k` invocation combines redirect following with disabled certificate checks, which can be abused to redirect the client to attacker-controlled infrastructure and download untrusted content. In the context of an agent skill that automatically retrieves a URL returned from prior API calls, this increases the blast radius because a compromised network path or manipulated endpoint can control what is written to disk.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
START=$(date +%s)
while true; do
  RESP=$(curl -sS -k --location "https://dashscope.aliyuncs.com/api/v1/tasks/$TASK_ID" \
    -H "Authorization: Bearer $DASHSCOPE_API_KEY")

  STATUS=$(echo "$RESP" | sed -n 's/.*"task_status"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)
Confidence
98% confidence
Finding
The script invokes curl with the -k flag, which disables TLS certificate validation for the HTTPS request to DashScope. This allows a man-in-the-middle attacker on the network path to intercept or modify the task status response, potentially exposing the Bearer API key and causing the script to trust attacker-controlled status or video URLs.

Missing User Warnings

High
Confidence
99% confidence
Finding
The curl command uses -k, which disables TLS certificate verification and allows an attacker on the network path to impersonate the DashScope endpoint. Because the request includes the Bearer API key and user content, a successful man-in-the-middle attack could steal credentials, tamper with submitted jobs, or return forged task IDs/results.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
DATA="{\"model\":\"$MODEL\",\"input\":{\"prompt\":\"$PROMPT\"$AUDIO_FIELD},\"parameters\":{\"size\":\"$SIZE\",\"prompt_extend\":$PROMPT_EXTEND,\"duration\":$DURATION,\"shot_type\":\"$SHOT_TYPE\"}}"

RESP=$(curl -sS -k --location "$API_URL" \
  -H 'X-DashScope-Async: enable' \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY" \
  -H 'Content-Type: application/json' \
Confidence
97% confidence
Finding
The dangerous tool parameter here is curl -k, which weakens the security guarantees of the network client by disabling certificate validation. In this skill, that is especially risky because the same request carries a live API credential and untrusted user-supplied content to a remote endpoint.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises and documents shell-based execution paths but does not declare any tool scope or allowed-tools restrictions. That creates an authorization gap where an agent may invoke shell capabilities more broadly than users or platform policy expect, increasing the chance of unintended command execution or file writes.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill encourages sending prompts, API credentials, and potentially user-supplied audio URLs to a third-party external service without an explicit warning in the description. This can cause users to disclose sensitive prompts or reference internal/private URLs without informed consent, creating privacy and data-governance risk.

External Transmission

Medium
Category
Data Exfiltration
Content
仅 wan2.6 系列模型支持此功能。通过设置 `prompt_extend: true` 和 `shot_type: "multi"` 启用。

```bash
curl --location 'https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis' \
  -H 'X-DashScope-Async: enable' \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY" \
  -H 'Content-Type: application/json' \
Confidence
90% confidence
Finding
The skill explicitly sends user-controlled content to an external API endpoint using curl with bearer-token authentication. In context, external transmission is expected for a video-generation skill, but it remains security-relevant because prompts, optional audio_url values, and associated metadata leave the local environment and may expose sensitive or internal information if users are not warned.

Context-Inappropriate Capability

Medium
Confidence
99% confidence
Finding
The script downloads a remote file with `curl -k`, which disables TLS certificate validation and allows a man-in-the-middle attacker to spoof the video host and supply arbitrary content. In this skill, the downloaded artifact is saved locally and presented as the generated media, so the insecure transport directly affects integrity of the output and could also expose the user to malicious files disguised as MP4 content.

External Transmission

Medium
Category
Data Exfiltration
Content
DATA="{\"model\":\"$MODEL\",\"input\":{\"prompt\":\"$PROMPT\"$AUDIO_FIELD},\"parameters\":{\"size\":\"$SIZE\",\"prompt_extend\":$PROMPT_EXTEND,\"duration\":$DURATION,\"shot_type\":\"$SHOT_TYPE\"}}"

RESP=$(curl -sS -k --location "$API_URL" \
  -H 'X-DashScope-Async: enable' \
  -H "Authorization: Bearer $DASHSCOPE_API_KEY" \
  -H 'Content-Type: application/json' \
Confidence
91% confidence
Finding
This script intentionally sends prompt data, optional audio_url metadata, and an authorization token to an external service. In a video-generation skill this external transmission is expected, but it still represents a real security/privacy boundary crossing, especially if users provide confidential text or internal resource references.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script transmits the user-supplied prompt and optional audio URL to Alibaba Cloud's external API, but provides no explicit warning, confirmation, or data-handling notice. In this skill context, users may include sensitive prompts or internal URLs, so silent exfiltration to a third party creates a real privacy and compliance risk.

Natural-Language Policy Violations

Low
Confidence
71% confidence
Finding
The skill description and title include Chinese phrases such as "百炼/通义万相/wan 文生视频" and "文生视频" alongside English, which can impose a language expectation in the skill's natural-language interface. Because there is no explicit opt-in or statement that the user may interact in their preferred language, this may conflict with language/locale choice policy.

Intent-Code Divergence

Low
Confidence
79% confidence
Finding
The comment at L52 says 'Build JSON (avoid jq dependency)', which suggests a simplified, dependency-light implementation. However, the script still depends on curl for network submission and sed/head for parsing the JSON response, so the inline documentation overstates how dependency-free the implementation is.

Static analysis

No suspicious patterns detected.