Back to skill

Security audit

Wan 2.6 & 2.5 — AI Video & Image Generation by Alibaba

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its image script can automatically use an undeclared Google provider and send prompts or local images there.

Review this before installing if your environment has a GEMINI_API_KEY or strict provider allowlists. Use explicit provider selection, avoid sensitive prompts or private media unless you approve third-party processing, and remember Atlas API usage is billed to the configured account.

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/generate_image.py:56
Finding
Undocumented Automatic Google Provider Can Transmit Local Images<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py:56-69`, `scripts/generate_image.py:229-271`, and `scripts/generate_image.py:441-454` **Vulnerability Type**: Undisclosed third-party data transmission and unsafe provider auto-selection **Risk Level**: Medium ### Vulnerable Code ```python def detect_provider(): """Auto-detect provider based on available API keys.""" has_atlas = bool(os.environ.get("ATLASCLOUD_API_KEY")) has_gemini = bool(os.environ.get("GEMINI_API_KEY")) if has_atlas and has_gemini: print("Note: Both API keys found. Defaulting to Atlas Cloud. Use --provider google to switch.") return "atlas" if has_atlas: return "atlas" if has_gemini: return "google" print("Error: No API key found. Set ATLASCLOUD_API_KEY or GEMINI_API_KEY.", file=sys.stderr) print(" Atlas Cloud: https://www.atlascloud.ai", file=sys.stderr) print(" Google AI Studio: https://aistudio.google.com/apikey", file=sys.stderr) sys.exit(1) ``` ```python def gemini_generate(prompt, params, output_dir, image_path=None): get_gemini_key() print(f"Submitting image generation (Google AI Studio): {GEMINI_MODEL}") # Build content parts parts = [] if prompt: parts.append({"text": prompt}) # If editing with a local image file if image_path: if image_path.startswith(("http://", "https://")): print("Error: Google AI Studio requires local file for editing, not URL.", file=sys.stderr) print("Use --provider atlas for URL-based editing.", file=sys.stderr) sys.exit(1) if not os.path.exists(image_path): print(f"Error: File not found: {image_path}", file=sys.stderr) sys.exit(1) with open(image_path, "rb") as f: img_b64 = base64.b64encode(f.read()).decode("utf-8") ext = os.path.splitext(image_path)[1].lower() mime_map = {".png": "image/png", ".jpg": "imag ...[truncated 4033 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Declare Google AI Studio in `SKILL.md`, including: - `GEMINI_API_KEY` as an optional credential. - `generativelanguage.googleapis.com` as a network destination. - The fact that prompts and complete local images can be transmitted. - Relevant data retention, billing, and privacy implications. 2. Require explicit provider selection for Google: ```python if not args.provider: provider = "atlas" else: provider = args.provider ``` Do not select a provider solely because an unrelated credential happens to exist in the environment. 3. Before transmitting a local file, display the exact file path, size, and destination host, and require affirmative consent unless an explicit noninteractive consent option was supplied. 4. Keep provider credentials isolated. Read `GEMINI_API_KEY` only after the user explicitly selects the Google provider. 5. Add a file-size limit and validate the local file's actual format before loading it entirely into memory. 6. Avoid mutating the caller's `params` dictionary through `pop()`. Copy and validate supported parameters so provider-specific behavior remains predictable. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/generate_image.py:309
Finding
API-Controlled Output URLs Are Downloaded Without Validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_image.py:202-212`, `scripts/generate_image.py:309-325`, `scripts/generate_video.py:166-183`, and `scripts/generate_video.py:325-327` **Vulnerability Type**: Unrestricted remote resource download **Risk Level**: Low ### Vulnerable Code ```python def atlas_generate(model_id, params, output_dir, timeout): get_atlas_key() prediction_id = atlas_submit(model_id, params) outputs = atlas_poll(prediction_id, timeout) if not outputs: print("Warning: No output files returned.", file=sys.stderr) return [] saved = [] for url in outputs: saved.append(download_file(url, output_dir)) return saved ``` ```python def download_file(url, output_dir="."): parsed = urllib.parse.urlparse(url) filename = os.path.basename(parsed.path) if not filename or "." not in filename: filename = f"output_{int(time.time())}.png" output_path = os.path.join(output_dir, filename) base, ext = os.path.splitext(output_path) counter = 1 while os.path.exists(output_path): output_path = f"{base}_{counter}{ext}" counter += 1 print(f"Downloading: {filename}") urllib.request.urlretrieve(url, output_path) size_kb = os.path.getsize(output_path) / 1024 print(f"Saved: {output_path} ({size_kb:.1f} KB)") return output_path ``` ```python def download(url, output_dir="."): parsed = urllib.parse.urlparse(url) filename = os.path.basename(parsed.path) if not filename or "." not in filename: filename = f"output_{int(time.time())}.mp4" output_path = os.path.join(output_dir, filename) base, ext = os.path.splitext(output_path) counter = 1 while os.path.exists(output_path): output_path = f"{base}_{counter}{ext}" counter += 1 print(f"Downloading: {filename}") urllib.request.urlretrieve(url, output_path) size_mb = os.path.getsize(output_path) / (1024 * 1024) prin ...[truncated 2432 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse every output URL and require: - Scheme exactly equal to `https`. - A nonempty hostname. - A hostname contained in a documented output-host allowlist. 2. Replace `urlretrieve()` with a streamed download implementation that enforces: - Connection and read timeouts. - A strict maximum byte count. - A limited redirect count. - Revalidation of the scheme and host after every redirect. 3. Validate the response `Content-Type` against the expected media category. 4. Inspect file signatures before finalizing the download. Reject content whose magic bytes do not match a supported image or video format. 5. Create local filenames and extensions from validated media types rather than trusting the remote URL path. 6. Download first to a securely created temporary file in the destination directory, validate it, and then atomically rename it to the final output path. 7. Consider resolving destination addresses and rejecting loopback, link-local, private, and other internal network ranges if provider output hosts are not strictly allowlisted. ]]>
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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
There is a material description-behavior mismatch. The description presents a broad Wan video-and-image generation skill centered on Alibaba Wan 2.6/2.5, with multiple video modalities and video-specific controls. The supplied code chunk only implements image generation/editing workflows and file upload/model listing, with Atlas Cloud and Google AI Studio providers. It does not generate, edit, transform, upload, or download videos, and contains no logic for duration, resolution, camera shots, audio guidance, or prompt expansion. The code’s actual primary purpose is image generation/editing, not the declared video-heavy multimodal Wan skill.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code substantially matches part of the description: it does support text-to-video, image-to-video, video-to-video, audio input, local file upload, model listing, polling, and downloading outputs through Atlas Cloud. However, the declared purpose is broader than the actual implementation. The script only targets video workflows via the /model/generateVideo endpoint and saves video outputs; there is no separate image-generation or image-editing path, no text-to-image endpoint, and no photo editing logic. Many claimed features such as prompt expansion, multi/single camera shot support, 1080p/15-second constraints, and support for 18 model variants are not directly implemented in code—they may be pass-through API parameters at best, but are not evidenced here. Because the description explicitly says to use the skill for generating/editing images and photos, while the code only implements video-related operations, this is a material description/behavior mismatch.

Vague Triggers

High
Confidence
98% confidence
Finding
The trigger text is extremely broad and could cause the skill to activate for generic image, video, marketing, or visual-content requests that may not specifically require this third-party integration. Because the skill sends prompts and media to an external paid API, over-triggering raises risks of unnecessary data disclosure, unexpected charges, and users unknowingly routing content to a third party.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares access to environment secrets and makes outbound network calls, but does not explicitly scope or constrain those capabilities with a permissions/allowed-tools declaration. In a skill that handles a billing-enabled API key and transmits user prompts and media to a third-party service, missing tool scoping increases the chance of unintended secret access or broader-than-expected external communication.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Step 1: Submit
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
94% confidence
Finding
This workflow explicitly sends prompts and authorization credentials to a third-party API and may upload user media for processing. In context, external transmission is expected for the feature, but it remains security-relevant because it exposes potentially sensitive user content and uses an account-wide billing key.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Step 1: Submit
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
94% confidence
Finding
This workflow explicitly sends prompts and authorization credentials to a third-party API and may upload user media for processing. In context, external transmission is expected for the feature, but it remains security-relevant because it exposes potentially sensitive user content and uses an account-wide billing key.

External Transmission

Medium
Category
Data Exfiltration
Content
### Image-to-Video Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
93% confidence
Finding
This example sends an image URL, prompt, and API credential to an external service for image-to-video generation. Even though that is the intended function, user-supplied media may contain sensitive or proprietary content, so automatic transmission to a third party has privacy and billing implications.

External Transmission

Medium
Category
Data Exfiltration
Content
### Video-to-Video Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
93% confidence
Finding
Video-to-video processing transmits source video URLs and prompts to a third-party API, which can expose sensitive recordings or proprietary media. Because video content often carries more identifying or confidential information than text alone, the context makes external transmission more sensitive here.

External Transmission

Medium
Category
Data Exfiltration
Content
### Audio-Guided Generation Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
91% confidence
Finding
Audio-guided generation transmits audio URLs and prompts externally, which may reveal copyrighted, confidential, or personal audio content. The inclusion of additional media types broadens the privacy surface and increases the chance that users unintentionally share sensitive data.

External Transmission

Medium
Category
Data Exfiltration
Content
### Text-to-Image Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateImage" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
92% confidence
Finding
This text-to-image example still sends user prompts and the authorization token to a third-party service, which can leak sensitive prompt content or incur charges. Although lower risk than direct media upload, prompts may still contain confidential business, personal, or regulated information.

External Transmission

Medium
Category
Data Exfiltration
Content
### Image Editing Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateImage" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
94% confidence
Finding
Image editing requires sending one or more source images to the remote API, which creates a direct privacy and confidentiality exposure for user-provided media. Because edited images may be personal photos or proprietary assets, this external transfer is materially security-relevant even if intentional.

External Transmission

Medium
Category
Data Exfiltration
Content
### Image-to-Video Flash Example (Wan 2.6)

```bash
curl -s -X POST "https://api.atlascloud.ai/api/v1/model/generateVideo" \
  -H "Authorization: Bearer $ATLASCLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
91% confidence
Finding
The flash image-to-video example also transmits user image content and prompts to the external provider. The faster or cheaper model variant does not reduce the underlying privacy and billing risk associated with sending user media off-platform.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a skill for generating both AI videos and images, including text-to-image and image editing across Wan 2.5/2.6 variants. This file only supports listing models, uploading media, submitting to a `/model/generateVideo` endpoint, polling video predictions, and downloading returned outputs; there is no image-generation or image-editing implementation here.

External Transmission

Medium
Category
Data Exfiltration
Content
import urllib.error
import urllib.parse

API_BASE = "https://api.atlascloud.ai/api/v1"


def get_api_key():
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
import urllib.error
import urllib.parse

API_BASE = "https://api.atlascloud.ai/api/v1"


def get_api_key():
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
import urllib.error
import urllib.parse

API_BASE = "https://api.atlascloud.ai/api/v1"


def get_api_key():
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Low
Confidence
83% confidence
Finding
The docstring says the script supports text-to-video, image-to-video, video-to-video, and local file upload, which can imply local files are accepted directly as generation inputs. In the implemented CLI, `generate` only accepts `--image`, `--video`, and `--audio` as URL strings, while local files must be uploaded separately via the `upload` command first.

Static analysis

No suspicious patterns detected.