Back to skill

Security audit

v2t

Security checks for vulnerabilities and agentic risk

Overview

This video transcription skill appears to do its advertised job, but it needs Review because it uploads user media to cloud storage while accepting broad remote URLs and making privacy and network-scope claims the code does not fully enforce.

Install only if you are comfortable sending the selected video, its local path metadata, and any downloaded remote-link content to the provider's cloud workflow. Avoid confidential, regulated, or internal videos unless the provider's retention and deletion promises are acceptable to you, and do not process untrusted URLs from other people because the downloader can reach network locations visible from your machine.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils/validator.js:3
Finding
Arbitrary URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-8`, `scripts/video2text/index.js:96-113`, `scripts/utils/download.js:317-331` **Vulnerability Type**: Server-Side Request Forgery through insufficient URL validation **Risk Level**: High ### Complete Code Snippet ```javascript // scripts/utils/validator.js:3-8 function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` ```javascript // scripts/video2text/index.js:96-113 if (validator.isUrl(file)) { const filepath = utils.downloadPath(); try { await fs.promises.mkdir(filepath, { recursive: true }); } catch (error) { utils.printError("临时下载目录创建失败: " + (error.message || String(error))); process.exit(1); } try { const downloadResult = await helper.download(file, filepath); let tempFilePath = downloadResult?.filePath || ""; if (tempFilePath === "") { utils.printError("下载失败: 未返回文件路径"); process.exit(1); } ``` ```javascript // scripts/utils/download.js:317-331 const req = this.__protocol.request(options, (response) => { if (this.__isRequireRedirect(response)) { redirectCount++; if (redirectCount > this.__opts.maxRedirects) { const err = new Error("Too many redirects"); this.__setState(this.__states.FAILED); this.emit("error", err); return reject(err); } const redirectedURL = /^https?:\/\//.test(response.headers.location) ? response.headers.location : new URL(response.headers.location, url).href; this.emit("redirected", redirectedURL, url); return getRequest(redirectedURL, getReqOptions(redirectedURL)); } ``` ### Technical Analysis The URL validator verifies only that the input uses the HTTP or HTTPS scheme. It does not resolve and inspect the destination address or reject loopback, private, link-local, reserved, or cloud metadata address rang ...[truncated 1957 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit HTTPS only unless HTTP support is strictly required. 2. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 ranges. 3. Explicitly block common metadata destinations, including `169.254.169.254`, but do not rely on a hostname or single-address blocklist alone. 4. Re-resolve and validate every redirect target before following it. 5. Protect against DNS rebinding by connecting to a validated, pinned address while preserving the expected TLS hostname. 6. Consider an allowlist of supported public media platforms and trusted content-delivery domains. 7. Reject URLs containing embedded credentials or unexpected ports. 8. Apply the same policy to preliminary requests, retries, resumed downloads, and redirects. 9. Run the downloader in a network-restricted sandbox that cannot access loopback, private networks, or metadata services. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/helper.js:27
Finding
Unbounded Remote Downloads Allow Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/helper.js:27-39`, `scripts/utils/download.js:526-549` **Vulnerability Type**: Unrestricted download size and duration **Risk Level**: Medium ### Complete Code Snippet ```javascript // scripts/utils/helper.js:27-39 async function download(url, path) { return new Promise((resolve, reject) => { const options = { retry: { maxRetries: constants.CREATE_MAX_ATTEMPTS, delay: constants.RETRY_INTERVAL, }, override: { skip: true, skipSmaller: true }, }; let progressLog = ""; const dl = new Downloader(url, path, options); ``` ```javascript // scripts/utils/download.js:526-549 const _fileName = this.__getFileNameFromHeaders(response.headers); this.__filePath = this.__getFilePath(_fileName); this.__fileName = this.__filePath.split(path.sep).pop(); if (fs.existsSync(this.__filePath)) { const downloadedSize = this.__getFilesizeInBytes(this.__filePath); if ( !this.__opts.override || (this.__opts.override.skip && (!this.__opts.override.skipSmaller || downloadedSize >= this.__total)) ) { this.__setState(this.__states.FINISHED); this.emit("skip", { fileName: this.__fileName, filePath: this.__filePath, totalSize: this.__total, downloadedSize, }); return resolve(true); } } if (this.__downloaded === 0) { this.__fileStream = fs.createWriteStream(this.__filePath, {}); } else { this.__fileStream = fs.createWriteStream(this.__filePath, { flags: "a" }); } ``` ### Technical Analysis The downloader writes remote response bodies to disk without enforcing a maximum number of bytes. The wrapper does not configure a file-size limit, validate the declared `Content-Length`, enforce an overall download deadline, verify available disk space, or reject missing and implausibly large lengths. A hostile endpoint can return a very large object, omit `Content-Length`, use chunked transfer encoding, or con ...[truncated 1694 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a strict maximum accepted video size based on documented service limits. 2. Reject responses whose `Content-Length` exceeds the limit before creating the output file. 3. Count bytes during streaming and immediately abort the request when the maximum is exceeded, including when `Content-Length` is absent or inaccurate. 4. Enforce both idle timeouts and a total download deadline. 5. Check available disk capacity before and during the download. 6. Delete partial files on every failure, timeout, cancellation, or threshold violation. 7. Validate the response media type and inspect the downloaded file signature before upload. 8. Limit retry attempts for responses that have already consumed substantial bandwidth. 9. Apply operating-system filesystem quotas and process-level resource limits as defense in depth. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/upload.js:10
Finding
Server-Controlled Presigned URL Can Redirect Local File Uploads to Arbitrary HTTPS Hosts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/video2text/index.js:140-149`, `scripts/utils/upload.js:10-40` **Vulnerability Type**: Unrestricted upload destination and forwarded server-controlled headers **Risk Level**: Medium ### Complete Code Snippet ```javascript // scripts/video2text/index.js:140-149 const presignedUrl = await video.getPresignedUrl(tokenValue, file); if (!presignedUrl || !presignedUrl?.url || presignedUrl.url === "") { throw new Error("获取预签名URL失败,请反馈给开发者"); } utils.printInfo("上传文件到安全空间..."); await upload.uploadFileToOSS(file, presignedUrl.url, presignedUrl.headers); utils.printInfo("文件上传到安全空间成功,获取视频分析任务ID"); ``` ```javascript // scripts/utils/upload.js:10-40 async function uploadFileToOSS(filename, presignedUrl, headers) { const url = new URL(presignedUrl); if (url.protocol !== "https:") { throw new Error("上传URL必须是HTTPS协议"); } return new Promise((resolve, reject) => { const fileStats = fs.statSync(filename); const totalSize = fileStats.size; let uploadedSize = 0; let settled = false; const fileStream = fs.createReadStream(filename); // 复制预签名 headers,并补充 OSS PUT 必需字段 const uploadHeaders = Object.assign({}, headers); // 关键修复:明确 Content-Length,否则 Node 对流式 body 默认使用 chunked // Transfer-Encoding,阿里云 OSS 预签名 PUT 通常会拒绝而返回 400/403 uploadHeaders["Content-Length"] = String(totalSize); if (!uploadHeaders["Content-Type"]) { uploadHeaders["Content-Type"] = "application/octet-stream"; } const options = { host: url.hostname, path: url.pathname + url.search, method: "PUT", headers: uploadHeaders, }; const req = https.request( { ...options, timeout: constants.REQUEST_TIMEOUT }, ``` ### Technical Analysis The upload destination and upload headers are obtained from the remote API. The client validates only that the returned URL uses HTTPS. It does not verify that the hostname belongs to an approved object-storage provider, ex ...[truncated 1843 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Allowlist exact object-storage hostname suffixes and validate the expected storage account and bucket. 2. Reject IP-literal destinations, unexpected ports, user-information components, and nonstandard URL forms. 3. Ensure hostname checks are boundary-aware; for example, accepting `.example.com` must not accept `example.com.attacker.test`. 4. Permit only the minimal headers required by the approved storage provider. 5. Reject dangerous or unnecessary server-provided headers rather than copying the entire object. 6. Verify that the final storage object URL belongs to the same approved storage scope before submitting it for processing. 7. Document every external domain contacted by the workflow. 8. Display or log the validated upload destination before transmitting sensitive local data. 9. Consider cryptographically binding the upload policy to the expected service account and object key. ]]>

other

Note
Location
scripts/api/video.js:11
Finding
Absolute Local File Paths Are Disclosed to the Remote API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/api/video.js:11-24`, `scripts/utils/request.js:81-95` **Vulnerability Type**: Unnecessary local filesystem metadata disclosure **Risk Level**: Low ### Complete Code Snippet ```javascript // scripts/api/video.js:11-24 async function getPresignedUrl(token, filename) { if (!token || typeof token !== "string") { throw new Error("token 必须是非空字符串"); } if (!filename || typeof filename !== "string") { throw new Error("filename 必须是非空字符串"); } const data = { file: filename }; const response = await requestApi( "/api/video/presign", token, data, ``` ```javascript // scripts/utils/request.js:81-95 const params = { _: Date.now(), skill_name: skillName() }; const fullPath = `${path}?${querystring.stringify(params)}`; const jsonData = JSON.stringify(data); const options = { host: constants.BASE_URL, path: fullPath, method: "POST", headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(jsonData), TOKEN: token, }, }; return await request(options, jsonData); ``` ### Technical Analysis The `filename` parameter is the complete local path passed to the command. It is serialized as the `file` property and sent to the external presign endpoint. An absolute path is not required to generate a remote object key or determine a media extension. A basename, extension, generated identifier, or sanitized logical filename would normally be sufficient. Sending the full path unnecessarily reveals local environment metadata. Potentially sensitive path components include operating-system usernames, organization names, customer names, project names, matter identifiers, and internal directory conventions. ### Attack Path 1. A user processes a file with a descriptive absolute path, such as `/home/user/Clients/Example/Confidential-Meeting.mp4`. 2. `getPresignedUrl()` places the entire path in the request body. 3. `postJson()` serializes the body a ...[truncated 639 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Send only `path.basename(filename)` after appropriate sanitization. 2. Prefer a generated opaque object identifier rather than a user-derived filename. 3. If the server needs format information, send only an allowlisted media extension or validated MIME type. 4. Remove directory separators and platform-specific path components before constructing the request. 5. Document all metadata transmitted to the remote service. 6. Add automated tests confirming that absolute paths, usernames, and parent-directory names never appear in outbound requests. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates token validation, promotional output, and workflow gating based on token state beyond the core advertised function. Mixing authentication checks with marketing/contact prompts can socially pressure users to disclose or obtain credentials through out-of-band channels, increasing phishing and trust-boundary risks in a skill that handles user media.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates token validation, promotional output, and workflow gating based on token state beyond the core advertised function. Mixing authentication checks with marketing/contact prompts can socially pressure users to disclose or obtain credentials through out-of-band channels, increasing phishing and trust-boundary risks in a skill that handles user media.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The finding indicates token validation, promotional output, and workflow gating based on token state beyond the core advertised function. Mixing authentication checks with marketing/contact prompts can socially pressure users to disclose or obtain credentials through out-of-band channels, increasing phishing and trust-boundary risks in a skill that handles user media.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates token validation, promotional output, and workflow gating based on token state beyond the core advertised function. Mixing authentication checks with marketing/contact prompts can socially pressure users to disclose or obtain credentials through out-of-band channels, increasing phishing and trust-boundary risks in a skill that handles user media.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates token validation, promotional output, and workflow gating based on token state beyond the core advertised function. Mixing authentication checks with marketing/contact prompts can socially pressure users to disclose or obtain credentials through out-of-band channels, increasing phishing and trust-boundary risks in a skill that handles user media.

Whitespace Padding

Medium
Category
Prompt Injection
Content
4. 同时传入文件路径与任务ID,优先执行 `--id`,忽略 `--file`
5. 无自定义 prompt 时,默认完整转录视频全部文字

| 用户自然语言指令                                         | 自动生成命令                                                                                                |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| 视频提取 https://example.com/video.mp4 中的文字          | `node scripts/video2text/index.js --file "https://example.com/video.mp4"`                                   |
| 把本地 /path/to/your/video.mp4 改成小红书风格的文案      | `node scripts/video2text/index.js --file "/path/to/your/video.mp4" --prompt "改写成小红书风格的文案"`       |
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill description does not prominently warn users that submitted videos or links are uploaded to a cloud service for processing. This undermines informed consent and can cause sensitive media to be transferred off-device unexpectedly, which is particularly risky for private meetings, interviews, or proprietary content.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The activation guidance fails to clearly disclose that online videos may be downloaded into a local temporary directory before being uploaded for processing. This creates hidden data-handling and storage behavior that may violate user expectations, local policy, or data-minimization requirements.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The document promises neutral error messages without marketing, yet elsewhere embeds website and WeChat contact information for token acquisition and support. In a security-sensitive workflow, this inconsistency weakens trust signals and can normalize off-platform contact or credential-related social engineering.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This file contains natural-language comments, exceptions, and help text entirely in Chinese, including user-facing CLI output such as error messages and usage/help text. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is clearly documented and justified, which is not present here.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This module performs HTTP/HTTPS requests to arbitrary URLs and writes the retrieved content to disk, including deleting partial files on stop or failure, but the code provides no confirmation prompt, print/log message, or explanatory comment warning users about these safety-relevant actions. Because these operations affect local files and transmit data to remote endpoints, the lack of disclosure in the code makes the behavior insufficiently transparent.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code emits user-facing error strings exclusively in Chinese, including operational guidance and remediation text. That creates a language policy violation when no user language choice or documented locale justification is present in the file.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The file emits all user-facing status and warning messages exclusively in Chinese, including the warning and recovery instructions. This is a natural-language locale policy concern because the skill does not provide user opt-in, fallback language support, or any documented justification that the skill is intended only for Chinese-speaking users.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The comment makes a strong privacy and retention promise for uploaded videos ('only used for transcription' and 'automatically deleted after completion'), but this module implements only upload behavior and provides no enforcement of deletion or data lifecycle controls. In a video-to-text skill handling potentially sensitive user media, such misleading assurances can cause privacy harm, regulatory exposure, and over-retention of user content if downstream deletion is absent or fails silently.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill sends user-supplied videos or public video links to a third-party cloud service for transcription, but the user-facing description does not clearly and prominently warn that media content is uploaded off-device for external processing. This can cause users to disclose sensitive recordings, personal data, or confidential meeting content without informed consent, especially because the skill is framed as a generic video-to-text utility and emphasizes convenience over data-sharing risk.

Whitespace Padding

Medium
Category
Prompt Injection
Content
## 7. 🗣️ 自然语言 → 命令(照这张表转)

| 用户说的话                                           | 就执行这条命令                                                                                              |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| 提取 https://example.com/video.mp4 里的文字          | `node scripts/video2text/index.js --file "https://example.com/video.mp4"`                                   |
| 总结这个视频的核心观点 https://example.com/video.mp4 | `node scripts/video2text/index.js --file "https://example.com/video.mp4" --prompt "总结这个视频的核心观点"` |
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Whitespace Padding

Medium
Category
Prompt Injection
Content
## 7. 🗣️ 自然语言 → 命令(照这张表转)

| 用户说的话                                           | 就执行这条命令                                                                                              |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| 提取 https://example.com/video.mp4 里的文字          | `node scripts/video2text/index.js --file "https://example.com/video.mp4"`                                   |
| 总结这个视频的核心观点 https://example.com/video.mp4 | `node scripts/video2text/index.js --file "https://example.com/video.mp4" --prompt "总结这个视频的核心观点"` |
Confidence
70% confidence
Finding
Large whitespace padding was detected (a block of blank lines or a long run of spaces). This can push injected instructions below or to the right of the visible area so a human reviewer never sees them while the agent still reads them. Manual review of the hidden content is recommended.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The README is entirely written in Chinese and all example prompts and invocation patterns assume Chinese-language use, but the documentation does not state that the skill is region-specific or provide any language/locale choice. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
L198 的规范约定写明“命名:name: video2text-ai”,而 manifest 顶部 L002 的实际名称是“v2t”。这不是单纯信息缺失,而是文档对技能标识的明确陈述与实际 frontmatter 相冲突,可能误导调用方或维护者。

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The file's docstrings and user-visible error/operation labels are written exclusively in Chinese, including status labels passed into API requests and thrown error messages. This can violate a language/locale policy when a skill enforces one language without offering the user a choice or documenting a justified locale restriction.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
This code contains natural-language comments and user-facing log/error strings entirely in Chinese, including operational notices about file cleanup and deletion failures. Because there is no indication that the skill is region-specific or that users can opt into this locale, it may violate the language/locale policy for skills expected to serve a broader audience.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This JavaScript file contains multiple user-visible status and error messages in Chinese, such as download progress, retry, resume, and failure notices. That can violate language/locale policy because the skill forces a specific language without offering opt-in or documenting a justified region-specific scope.

Natural-Language Policy Violations

Low
Confidence
96% confidence
Finding
The banner string is explicitly in Chinese ("视频文案智能提取助手"), which indicates a fixed language choice in user-facing output. Under the policy rules, hard-coding a specific language without opt-in or documented locale justification is a natural-language policy violation.

Static analysis

No suspicious patterns detected.