Back to skill

Security audit

one-number-explains-video-gen

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its video-generation purpose, but its helper script can upload arbitrary local files to WeryAI when given a non-HTTPS image value.

Install only if you are comfortable using a paid WeryAI API key and sending prompts, image URLs, and any explicitly approved local image files to WeryAI. Prefer public HTTPS image URLs and avoid passing local paths until the script adds an enforced consent flag and image/path validation.

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

Error
Location
scripts/video_gen.js:140
Finding
Unrestricted Local File Upload Without Enforced Consent or Image Validation## Vulnerability Details **File Location**: `scripts/video_gen.js:140-149, 206-251, 273-283, 378-384` **Vulnerability Type**: Arbitrary local file disclosure through automatic remote upload **Risk Level**: High ### Vulnerable Code ```js function normalizeLocalFilePath(value) { if (typeof value !== 'string' || !value.trim()) return null; if (value.startsWith('file://')) { return new URL(value); } return path.resolve(value); } function inferMimeType(filePath) { return IMAGE_MIME_TYPES[path.extname(filePath).toLowerCase()] || 'application/octet-stream'; } ``` ```js async function uploadFileToPublicUrl(inputPath, apiKey) { const resolvedPath = normalizeLocalFilePath(inputPath); if (!resolvedPath) { throw new Error(`Invalid local image path: ${inputPath}`); } const filePath = resolvedPath instanceof URL ? fileURLToPath(resolvedPath) : path.resolve(resolvedPath); let stat; try { stat = await fs.stat(filePath); } catch { throw new Error(`Local image file not found: ${inputPath}`); } if (!stat.isFile()) { throw new Error(`Local image path is not a file: ${inputPath}`); } const fileBuffer = await fs.readFile(filePath); const fileName = path.basename(filePath); const mimeType = inferMimeType(filePath); const form = new FormData(); form.append('batch_no', makeUploadBatchNo()); form.append('fixed', 'false'); form.append('file', new Blob([fileBuffer], { type: mimeType }), fileName); const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 60_000); let res; try { res = await fetch(MODELS_BASE_URL + UPLOAD_API_PATH, { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, }, body: form, signal: controller.signal, }); ``` ```js async function ensurePublicImageUrl(value, apiKey) { if (typeof value !== 'string' || !value.trim()) { throw new Error('Image source must be a non-empty string.'); } if (isPubl ...[truncated 3917 chars]
Remediation
## Remediation Suggestions 1. **Disable local paths by default.** Reject every image value that is not a valid public HTTPS URL during normal operation. 2. **Require an explicit capability flag.** Gate local uploads behind a clearly named option such as `--allow-local-upload`. The flag should not be inferred from the presence of a path. 3. **Enforce informed consent.** Before enabling the capability, show the exact resolved path, destination host, and warning that the service may return a public URL. For Agent-driven noninteractive use, require a separate trusted-layer authorization rather than treating JSON content as consent. 4. **Restrict filesystem scope.** Resolve canonical paths with `fs.realpath()` and require files to reside within an operator-approved upload directory. Reject path traversal, symlink escapes, device files, and paths outside that directory. 5. **Enforce actual image types.** Permit only required image formats and validate content using magic bytes or a trusted image decoder. Remove the `application/octet-stream` fallback and reject files whose extension and detected content disagree. 6. **Apply resource limits.** Check file size before reading, impose a conservative maximum upload size, and use streaming where supported to avoid loading an entire untrusted file into memory. 7. **Separate commands and privileges.** Consider moving local upload into a distinct command or helper that can run with narrower filesystem access. The primary generation commands should accept only HTTPS URLs. 8. **Improve dry-run warnings.** Display the canonical local path, expected destination, detected type, and size without reading or uploading file content. 9. **Test the security boundary.** Add automated tests confirming that sensitive paths, unsupported file types, symlink escapes, and local paths without the explicit authorization flag are rejected.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill is presented as a narrowly scoped data-hook video generator, but its documented behavior includes broader remote media generation, local image upload to third-party storage, polling, and retrieval workflows. This mismatch can mislead users and reviewers about the real data flows, causing them to approve a skill that may transmit user-supplied or local content externally without fully informed consent.

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. **`scripts/video_gen.js`** + **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_API.md)**. **No other Cursor ski
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill declares it needs environment secrets and network access but does not constrain tool scope with explicit permissions or allowed-tools. In an agent setting, this creates unnecessary ambiguity about what the skill may invoke and increases the chance of unintended secret access or outbound data transfer, especially since it can call a remote video API and potentially handle local images.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Line L136 says to translate a user's Chinese brief to English on-screen lines unless otherwise specified. This imposes a language choice by default rather than offering the user an explicit language or locale opt-in, which matches the language-policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The evaluation requires English subtitles as a fixed behavior without indicating that subtitle language should follow user preference or context. This creates an unnecessary locale restriction that can mis-handle multilingual requests and cause the skill to impose output characteristics the user did not ask for.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The implicit trigger prompts are broad enough to match ordinary requests for short-form video creation, not just the specialized 'one-number explains' skill. This can cause unintended invocation, leading the agent to apply this skill in contexts the user did not request, reducing precision and potentially overriding more appropriate workflows or user preferences.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The documentation explicitly describes a code path where non-HTTPS image inputs are treated as local file paths, read from disk, and uploaded to a remote service before video generation. That expands the effective capability of the skill from using public image URLs to handling arbitrary local files, which can cause unintended local file exfiltration if an agent passes user- or model-supplied paths without strong consent and validation.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
Permitting local disk reads and remote upload is broader than what is needed for a 'one-number explainer video' skill and introduces a data-boundary crossing: local content can be sent to an external API. In an agent setting, this creates risk that sensitive local images or files are uploaded due to prompt injection, misunderstanding, or insufficient user awareness.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script exposes a broad, general-purpose WeryAI video generation CLI, including model enumeration, arbitrary text/image submission, file upload, and task polling, which exceeds the declared one-number short-form data-hook skill scope. In an agent-skill context, this scope expansion increases the attack surface and enables misuse of the skill as an unconstrained external-content generation and file-upload tool rather than a narrowly bounded capability.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
Request construction only forwards generic fields such as prompt, model, duration, aspect ratio, resolution, audio, negative prompt, and image inputs. There is no logic for creating captions, synchronizing timed subtitles, or enforcing English-language caption output despite the manifest explicitly advertising that capability.

Static analysis

No suspicious patterns detected.