Back to skill

Security audit

outfit-transition-video

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed paid WeryAI video generator, but it needs Review because its helper script can upload any readable local file supplied as an image path to WeryAI without an enforced consent or image-only guard.

Review before installing. Use this skill only if you are comfortable providing a WeryAI API key and making paid network calls. Prefer public HTTPS image URLs; do not pass local paths unless you intentionally want that exact file uploaded to WeryAI, ideally from an isolated working directory or container.

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:196
Finding

Arbitrary Local File Upload Through Image Input

Content
View full analysis

Vulnerability Details

File Location: scripts/video_gen.js, lines 196–245 and 273–283
Vulnerability Type: Arbitrary readable-file disclosure to an external service
Risk Level: High

Vulnerable Code

js
function inferMimeType(filePath) {
  return IMAGE_MIME_TYPES[path.extname(filePath).toLowerCase()] || 'application/octet-stream';
}

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,
    });
  } catch (err) {
    clearTimeout(timer);
    if (err.name === 'AbortError') {
      throw new Error(`Upload timeout: ${filePath}`);
    }
    throw err;
  }
  clearTimeout(timer);
js
async function ensurePublicImageUrl(value, apiKey) {
  if (typeof value !== 'string' || !value.trim()) {
    throw new Error('Image source must be a non-empty string.');
  }
  if (isPublicHttpsUrl(value)) return value;
  if (isRemote
...[truncated 3962 chars]
Remediation
View remediation

Remediation Suggestions

  1. Disable local paths by default. Require image and every images[] entry to be a public HTTPS URL unless the operator explicitly enables local upload.

  2. Add an explicit capability flag. Require a command-line option such as --allow-local-upload; reject local paths when the flag is absent. Do not infer consent merely from the presence of a path.

  3. Require an interactive or external confirmation step. Before reading a file, display its canonical path, size, detected type, and upload destination. Require affirmative confirmation unless a trusted non-interactive policy explicitly authorizes the operation.

  4. Restrict access to an approved directory. Resolve both the approved root and requested path with fs.realpath(), then verify that the requested file remains inside that root. Reject traversal outside it.

  5. Reject symbolic links. Use fs.lstat() and fail if the selected path is a symbolic link. Revalidate the opened file to reduce time-of-check/time-of-use risks.

  6. Enforce image-only validation. Allow only documented image extensions and verify magic bytes for JPEG, PNG, WebP, and GIF before uploading. Do not fall back to application/octet-stream.

  7. Enforce file-size and resource limits. Reject unexpectedly large files before fs.readFile(), or stream uploads with a strict byte limit to avoid excessive memory consumption.

  8. Separate upload authorization where possible. Use a narrowly scoped credential for file uploads rather than a general-purpose generation credential, subject to WeryAI API support.

  9. Align tests and documentation with runtime behavior. Add negative tests proving that files such as .env, private keys, files outside the approved directory, symlinks, and files with forged image extensions are rejected.

  10. Prefer removing the feature if unnecessary. Public HTTPS image URLs already satisfy the declared image-to-video workflow and represent the minimum-priv ...[truncated 13 chars]

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared purpose frames the skill as a narrow outfit-transition generator, but the documented behavior expands into broader video generation, model listing, polling/status operations, image and multi-image submission, and possible local file upload to external storage. This mismatch can mislead users and security reviewers about what data leaves the system and what actions the skill can perform, increasing the chance of unauthorized uploads, privacy issues, and unexpected paid operations.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 22)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 27)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 34)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 36)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 41)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 67)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 73)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 74)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 75)May include surrounding context.

md
**Dependencies:** `WERYAI_API_KEY` + Node.js 18+. When you run the CLI, **`scripts/video_gen.js`** must exist; **[`WERYAI_VIDEO_API.md`](resources/WERYAI_VIDEO_

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 89)May include surrounding context.

md
- Do not hard-code absolute paths in this doc; run from the skill package root (next to `SKILL.md`) so `scripts/` and `resources/` paths resolve.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill declares no explicit tool scope despite requiring environment access and outbound network use. That omission weakens least-privilege controls and informed consent, making it easier for an installer or agent runtime to grant broader capabilities than users expect, especially since the skill may also handle local files and paid API calls.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The implicit trigger example is broad enough that normal user requests about outfit-change or fashion-transition videos could activate the skill without clear user intent to use this specific capability. In an agent environment, overbroad trigger patterns can cause unintended tool invocation, reduce user control, and route unrelated prompts into media-generation flows that may have different safety, cost, or policy implications.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This documentation explicitly enables a local-file code path where the script reads arbitrary files from disk and uploads them to an external endpoint before video generation. In the context of an outfit-transition video skill, that behavior expands the trust boundary beyond the manifested purpose and can lead to unintended disclosure of local images or other files if an agent is induced to pass local paths.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documented feature allows reading files from the local filesystem and transmitting them to a separate upload service, but this capability is not clearly necessary for generating outfit-transition videos. That mismatch increases the risk that a general-purpose agent could be socially engineered into exfiltrating local content under the guise of image input.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.