Back to skill

Security audit

Vidu Video Generation Provider

Security checks for vulnerabilities and agentic risk

Overview

The plugin is a coherent Vidu video generator, but it needs Review because it downloads a provider-supplied video URL without clear destination or size controls.

Install only if you are comfortable sending prompts and uploaded images/videos to Vidu. Prefer use in an environment where provider-directed downloads cannot reach internal services, and ask the publisher to validate generated-video URLs, block private-network destinations and redirects, cap download size, and document data handling clearly.

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

Warning
Location
video-generation-provider.ts:127
Finding
Server-Side Request Forgery Through an Unvalidated Generated-Video URL<![CDATA[ ## Vulnerability Details **File Location**: `video-generation-provider.ts:127-141` and `video-generation-provider.ts:358-367` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: Medium ### Vulnerable Code ```ts async function downloadViduVideo(params: { url: string; timeoutMs?: number; fetchFn: typeof fetch; }): Promise<GeneratedVideoAsset> { const response = await fetchWithTimeout( params.url, { method: "GET" }, params.timeoutMs ?? DEFAULT_TIMEOUT_MS, params.fetchFn, ); await assertOkOrThrowHttpError(response, "Vidu generated video download failed"); const mimeType = normalizeOptionalString(response.headers.get("content-type")) ?? "video/mp4"; const arrayBuffer = await response.arrayBuffer(); return { buffer: Buffer.from(arrayBuffer), mimeType, fileName: `video-1.${mimeType.includes("webm") ? "webm" : "mp4"}`, }; } ``` The remotely supplied URL reaches this function here: ```ts const videoUrl = normalizeOptionalString(completed.creations?.[0]?.url); if (!videoUrl) { throw new Error("Vidu video generation completed without a video URL"); } const video = await downloadViduVideo({ url: videoUrl, timeoutMs: req.timeoutMs, fetchFn, }); ``` ### Technical Analysis The generated-video URL comes from `completed.creations[0].url`, which is controlled by the remote API response. The plugin passes this URL directly to `fetchWithTimeout` without validating its protocol, hostname, resolved IP address, port, or redirect chain. Creation requests use `resolveProviderHttpRequestConfig` and explicitly set `allowPrivateNetwork: false`. The generated-video download does not apply the same dispatcher policy or private-network restriction. Consequently, the protection covering the initial Vidu API request is not visibly applied to this secondary request. If the API response can be manipulated—for example, through compromise of the provider, a malicious configured endpoint, or another u ...[truncated 1870 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply the same SSRF-resistant HTTP policy used for provider requests to generated-asset downloads, including private-network blocking and the SDK dispatcher policy. 2. Require the URL to use HTTPS and reject embedded credentials, unsupported ports, malformed hostnames, and non-HTTP schemes. 3. Allowlist documented Vidu asset-delivery domains where operationally possible. Do not rely solely on hostname suffix matching. 4. Resolve the destination and reject loopback, private, link-local, multicast, carrier-grade NAT, documentation, and other reserved address ranges for both IPv4 and IPv6. 5. Repeat destination validation after every redirect and limit the number of redirects. This prevents a public URL from redirecting to an internal address. 6. Protect against DNS rebinding by ensuring that the validated address is the address used by the network connection. 7. Enforce a strict maximum response size before and during download. Abort streaming once that limit is exceeded rather than buffering an unlimited response. 8. Validate the returned media type and, where practical, inspect the file signature before accepting the response as a video. 9. Avoid returning the remote source URL in metadata unless downstream consumers require it; otherwise, it may expose signed URLs or asset identifiers. 10. Add tests covering loopback, RFC 1918, IPv6 local addresses, cloud metadata endpoints, redirects to private destinations, DNS rebinding scenarios, and oversized responses. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill documentation describes a third-party video generation provider but does not clearly warn users that their prompts and uploaded media will be transmitted to Vidu's external API endpoints. This can lead to unintended disclosure of sensitive text, images, or reference assets, especially because the plugin explicitly supports image, reference, and start/end frame uploads and multiple remote endpoints.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The generateVideo flow transmits req.prompt plus image/video inputs to Vidu via HTTP requests and also downloads generated media from returned URLs. This file contains no confirmation prompt, user-facing log, or comment/docstring warning that user content is sent to a third-party service.

Vague Triggers

Low
Confidence
77% confidence
Finding
This manifest file falls under the vague-trigger category, and it declares the skill enabled by default without any accompanying description of when it should or should not activate. Because the manifest provides no explicit trigger phrases, context limits, or exclusion conditions, the activation scope is underspecified and may allow unintended invocation behavior in host systems that rely on manifest metadata.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"type": "module",
  "license": "MIT-0",
  "devDependencies": {
    "openclaw": "^2026.4.15",
    "typescript": "^5.8.0",
    "vitest": "^3.1.0"
  },
Confidence
91% confidence
Finding
The manifest uses a caret range for the openclaw devDependency, which allows newer compatible releases to be installed without review. This weakens build reproducibility and can unexpectedly pull in a vulnerable or compromised release, especially notable here because separate advisories exist for this package.

Unverifiable Dependency: openclaw has 16 known advisory(ies) (CVE-2026-53846 (OpenClaw: Workspace .env npm_execpath could influence bundled runtime dependency); CVE-2026-32064 (OpenClaw's andbox browser noVNC observer lacked VNC authentication); CVE-2026-32006 (OpenClaw has a BlueBubbles group allowlist mismatch via DM pairing-store fallbac) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
87% confidence
Finding
The package references openclaw with a non-exact version while public advisories exist for that dependency. Without exact pinning and a lockfile, it is not possible to verify whether the resolved version includes fixes or remains affected, leaving consumers unable to assess exposure reliably.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"license": "MIT-0",
  "devDependencies": {
    "openclaw": "^2026.4.15",
    "typescript": "^5.8.0",
    "vitest": "^3.1.0"
  },
  "openclaw": {
Confidence
84% confidence
Finding
The typescript devDependency is specified with a caret range, so installs may resolve to different versions over time. While this is primarily a supply-chain hygiene issue rather than an immediate exploit, it reduces reproducibility and may introduce unreviewed changes into the development toolchain.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"devDependencies": {
    "openclaw": "^2026.4.15",
    "typescript": "^5.8.0",
    "vitest": "^3.1.0"
  },
  "openclaw": {
    "extensions": [
Confidence
89% confidence
Finding
The vitest devDependency is unpinned, allowing semver-compatible updates to be installed automatically. Because test frameworks can execute project code and may expose local services or files during development, pulling an unintended version can increase supply-chain and local-environment risk.

Unverifiable Dependency: vitest has 3 known advisory(ies) (CVE-2026-47429 (When Vitest UI server is listening, arbitrary file can be read and executed); CVE-2026-84373 (Vitest: Path Traversal / Arbitrary File Read via @vitest/mocker Redirect Mock); CVE-2025-24964 (Vitest allows Remote Code Execution when accessing a malicious website while Vit)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
85% confidence
Finding
Vitest has known advisories, and the manifest does not fix the dependency to a verifiable exact release. That makes the actual security posture of the development environment uncertain and can expose maintainers to vulnerable test tooling if an affected version is resolved.

Static analysis

No suspicious patterns detected.