Back to skill

Security audit

guaikei-video2text

Security checks for vulnerabilities and agentic risk

Overview

This video transcription skill mostly matches its stated purpose, but its URL downloading and upload flow are under-scoped and could expose private network data, local path metadata, or consume excessive disk space.

Review before installing. Use this only if you are comfortable sending video files, prompts, task IDs, the API token, and some file metadata to the GuaiKei service and its presigned storage backend. Do not give it internal, localhost, cloud-metadata, or otherwise private URLs; prefer trusted public media URLs or local files. Avoid confidential videos unless you have independently verified the provider's retention and deletion promises, and monitor the skill tmp directory and disk usage for large downloads.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/utils/validator.js:3
Finding
Arbitrary URL Fetching Enables SSRF and External Disclosure of Internal Responses<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-7`, `scripts/video2text/index.js:98-108`, `scripts/utils/download.js:483-493`, `scripts/video2text/index.js:140-154` **Vulnerability Type**: Server-Side Request Forgery (SSRF) with external data transfer **Risk Level**: High ### Vulnerable Code ```js // scripts/utils/validator.js:3-7 function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` ```js // scripts/video2text/index.js:98-108 if (validator.isUrl(file)) { const filepath = utils.downloadPath(); try { await fs.promises.mkdir(filepath, { recursive: true }); } catch (error) { utils.printError("Temporary download directory creation failed: " + (error.message || String(error))); process.exit(1); } try { const downloadResult = await helper.download(file, filepath); ``` ```js // scripts/utils/download.js:483-493 if (this.__isRequireRedirect(response)) { this.__redirectCount++; if (this.__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, this.url).href; this.__isRedirected = true; this.__initProtocol(redirectedURL); this.emit("redirected", redirectedURL, this.url); return this.__start(); } ``` ```js // scripts/video2text/index.js:140-154 const presignedUrl = await video.getPresignedUrl(tokenValue, file); if (!presignedUrl || !presignedUrl?.url || presignedUrl.url === "") { throw new Error("Failed to obtain presigned URL; report this to the developer"); } utils.printInfo("Uploading file to secure storage..."); await upload.uploadFileToOSS(file, presignedUrl.url, presignedUrl. ...[truncated 2610 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an explicit allowlist of supported public video-hosting domains. 2. If arbitrary public URLs are required, resolve the hostname before connecting and reject: - IPv4 loopback, private, link-local, multicast, carrier-grade NAT, reserved, and documentation ranges. - IPv6 loopback, unique-local, link-local, multicast, IPv4-mapped private addresses, and other reserved ranges. - Known cloud metadata addresses and hostnames. 3. Apply the same validation to every redirect destination. 4. Limit redirects and reject redirects that change to a disallowed protocol, host, address class, or port. 5. Protect against DNS rebinding by connecting to the validated resolved address while preserving the original hostname for TLS verification and the HTTP `Host` header. 6. Reject URLs containing embedded credentials and reject nonstandard ports unless explicitly required. 7. Validate the response MIME type and media signature before storing or uploading it. 8. Consider processing remote video URLs server-side in an isolated network with no access to private address ranges. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/download.js:464
Finding
Unbounded Remote Downloads Permit Disk and Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/helper.js:29-37`, `scripts/utils/download.js:464-475`, `scripts/utils/download.js:547-574`, `scripts/config/constants.js:8` **Vulnerability Type**: Unrestricted download size and temporary-file resource exhaustion **Risk Level**: Medium ### Vulnerable Code ```js // scripts/utils/helper.js:29-37 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); ``` ```js // scripts/utils/download.js:464-475 return this.__protocol.request(this.__reqOptions, (response) => { this.__response = response; if (!this.__isResumed) { this.__total = parseInt(response.headers["content-length"]) || null; this.__resetStats(); } if (this.__isResumed && response.statusCode === 200) { this.__isResumed = false; this.__total = parseInt(response.headers["content-length"]) || null; this.__resetStats(); } ``` ```js // scripts/utils/download.js:547-574 this.__fileStream = fs.createWriteStream(this.__filePath, {}); } else { this.__fileStream = fs.createWriteStream(this.__filePath, { flags: "a" }); } this.emit("download", { fileName: this.__fileName, filePath: this.__filePath, totalSize: this.__total, isResumed: this.__isResumed, downloadedSize: this.__downloaded, }); this.__retryCount = 0; this.__isResumed = false; this.__isRedirected = false; this.__setState(this.__states.DOWNLOADING); this.__statsEstimate.time = new Date(); this.__statsEstimate.throttleTime = new Date(); readable.on("data", (chunk) => this.__calculateStats(chunk.length)); this.__pipes.forEach((pipe) => { readable.pipe(pipe.stream, pipe.options); readable = pipe.stream; }); readable.pipe(this.__fileStream); readable.on("error", this.__onError(resolve, reject)); this.__fileStream.on("finish", this.__onFinished(resolve, reject)); ...[truncated 1861 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a strict, configurable maximum video size appropriate for the service. 2. Reject responses whose declared `Content-Length` exceeds the limit before creating the output file. 3. Count actual received bytes and immediately destroy the response, request, and output stream when the limit is crossed. 4. Enforce an overall transfer deadline in addition to socket inactivity timeouts. 5. Require an approved media MIME type and verify the downloaded file's signature before upload. 6. Delete partial files on size-limit violations, timeouts, aborted requests, and all other failures. 7. Limit concurrent downloads and uploads. 8. Check available disk space before starting large transfers. 9. Shorten temporary-file retention and remove successfully uploaded temporary downloads immediately when they are no longer needed. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/api/video.js:11
Finding
Full Local File Paths Are Unnecessarily Disclosed to the Remote API<![CDATA[ ## Vulnerability Details **File Location**: `scripts/api/video.js:11-27`, `scripts/video2text/index.js:140` **Vulnerability Type**: Excessive disclosure of local filesystem metadata **Risk Level**: Low ### Vulnerable Code ```js // scripts/api/video.js:11-27 async function getPresignedUrl(token, filename) { if (!token || typeof token !== "string") { throw new Error("token must be a non-empty string"); } if (!filename || typeof filename !== "string") { throw new Error("filename must be a non-empty string"); } const data = { file: filename }; const response = await requestApi( "/api/video/presign", token, data, constants.CREATE_MAX_ATTEMPTS, "pre-upload", ); ``` ```js // scripts/video2text/index.js:140 const presignedUrl = await video.getPresignedUrl(tokenValue, file); ``` ### Technical Analysis When the user selects a local file, the `file` variable may contain its complete absolute path. That value is included unchanged in the JSON body sent to `www.guaikei.com`. A presign service generally needs only a sanitized base filename, media extension, MIME type, or generated object key. The directory portion of a local path is not needed to upload the file and may expose usernames, home-directory structure, project names, customer names, or other organizational metadata. ### Attack Path 1. A user processes a local file whose path contains sensitive contextual information, such as `/home/alice/confidential-client/board-meeting.mp4`. 2. The CLI passes the complete path to `getPresignedUrl()`. 3. The method sets `data.file` to the unchanged path. 4. `requestApi()` sends the JSON body to the remote service. 5. The remote service receives filesystem metadata unrelated to the video content itself. ### Impact Assessment This issue does not grant additional local privileges. Its impact is limited to unnecessary disclosure of environmental and organizational metadata to the remote API, including: - Local usernames ...[truncated 282 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Send only `path.basename(filename)` after sanitizing control characters and path separators. 2. Prefer generating an opaque random object name and retaining only a validated media extension. 3. Send the MIME type and file size as separate validated fields if the presign service requires them. 4. Document every metadata field transmitted to the service. 5. Add tests confirming that absolute directory information never appears in outbound API payloads. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
声明描述的是一个视频转文字/文案生成技能,核心能力应包括视频输入处理、音视频转写、内容清洗、总结改写或结构化输出。但给出的代码仅实现了通用 CLI 参数解析器:识别命令行选项、处理默认值、布尔值、--flag=value 语法、位置参数、帮助文本生成及报错逻辑。该代码既未体现任何视频下载/读取、音频提取、语音识别、大模型调用,也没有文案生成相关行为。因此,这段代码的实际行为与声明用途存在明显且实质性的不一致。

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述聚焦于视频转文字、内容提取和文案生成能力;而这段代码并未体现任何视频解析、音视频转写、字幕提取、调用大模型、文本清洗、总结改写或翻译逻辑。相反,它是一个独立的下载组件,会对外部 URL 发起网络请求并将响应内容保存到本地文件系统,还支持重试、续传、暂停/恢复等下载能力。这属于与声明主用途明显不同的实际行为,并且涉及未在描述中体现的通用文件下载与本地文件管理能力。因此应判定为描述与代码行为不一致。

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
声明描述的是一个以视频转写和文案生成为核心的技能,但提供的代码片段只是一个辅助工具:读取并缓存 package.json 中的名称字段。该代码没有体现任何与视频输入、模型调用、文本清洗、摘要、改写、翻译或结构化文案生成相关的行为。虽然读取 package.json 可能属于内部支持性实现,但当前所给代码片段本身与声明的主要用途明显不一致,因此应判定为描述与实际行为不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
声明描述的是视频转写与内容生成类能力,但提供的代码片段只实现了 token 格式校验和控制台提示,且包含明显的商业推广信息。该行为与视频转文字、字幕提取、总结分析等核心功能没有直接对应关系。虽然 token 校验可能属于配套基础设施,但当前代码片段的实际可见功能与声明的主要用途严重不一致,因此应判定为描述与行为不匹配。

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.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The trigger text includes broad requests like '会议纪要' and '内容分析' without requiring a video or audio input, which can cause the agent to invoke this skill for unrelated user content. In context, that increases the chance of unnecessary transmission of user data to a third-party service and misrouting of tasks outside the intended media-processing scope.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation guidance explicitly tells the AI to prioritize this skill for broad intent categories, but it does not strictly require a video/audio source. That can lead to overbroad invocation, causing sensitive text-only tasks to be inappropriately routed to an external service and increasing privacy and data-governance risk.

Whitespace Padding

Medium
Category
Prompt Injection
Content
当用户用自然语言下达指令时,按以下映射生成命令,保证识别与执行一致:

| 用户自然语言指令                                     | 生成的命令                                                                                                  |
| ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| 提取 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

Medium
Confidence
86% confidence
Finding
The package description is entirely in Chinese and states the skill produces outputs such as summaries, rewrites, and Chinese-English translation, but the metadata does not indicate any user-selectable language or locale option. This can be a language-policy concern because it implies a fixed language/locale experience without explicit opt-in or documented limitation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This JavaScript file hardcodes user-facing comments, error messages, and help output in Chinese, including thrown errors and CLI help text. Because there is no visible mechanism for language selection or documented locale constraint, the skill appears to enforce a specific language, which matches the policy-violation category for language/locale restrictions.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This file contains natural-language comments and runtime messages entirely in Chinese, including user-facing notices about deletion and disk usage. Under the stated policy, forcing a specific language without user opt-in or documented locale justification is a language-policy violation.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The stop path deletes the partially downloaded file with fs.unlink when removeOnStop is enabled, and similar cleanup deletion occurs on failure, yet the file provides no visible warning, confirmation, or user-facing message about this destructive behavior. Silent deletion is safety-relevant because it can remove user-visible artifacts unexpectedly.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code performs a safety-relevant operation by fetching data from a remote URL and writing it to a local file via createWriteStream, but the file contains no confirmation prompt, print/log statement, or explanatory comment/docstring warning users about that behavior. For a reusable utility, silently persisting network-retrieved content to disk can affect user data and system state without visible disclosure.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This file contains natural-language comments and runtime status/error messages exclusively in Chinese, such as the doc comment and download progress strings. Because the skill does not offer any language choice or document that it is intentionally limited to a Chinese-speaking context, it creates a language-policy issue under the requirement to avoid forcing a specific language without user opt-in.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The code builds and sends an HTTPS POST request containing serialized request data and a TOKEN header, which transmits user or system data to a remote service. Within this file there is no confirmation prompt, user-facing notice, or explanatory comment/docstring describing that outbound network transmission and credential use occur.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The skill emits all user-facing status and warning messages exclusively in Chinese, including critical configuration guidance. This imposes a language choice on users without opt-in or justification, which fits the policy category for language/locale violations.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The comment makes strong privacy and data-handling promises ('not leaked, not retained, automatically deleted after processing') that are not implemented or enforced anywhere in this function. In a video-to-text skill that handles potentially sensitive user videos, this creates a security/privacy gap: operators or downstream services may retain or reuse uploaded content despite the code suggesting otherwise, leading to user deception and potential policy or compliance violations.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This README presents all instructions, warnings, and examples only in Chinese, which can amount to a language/locale policy issue when the skill implicitly forces a specific language for all users. The file does not offer an alternative language, opt-in, or justification that the skill is limited to a Chinese-only audience or region.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Multiple hard-coded natural-language strings in this file are only in Chinese, including operational and error messages. That imposes a specific language on users without any visible locale choice or justification, which conflicts with the language/locale policy criteria.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The banner text is hard-coded in Chinese, which imposes a specific language on users without any visible opt-in or localization mechanism. Under the natural-language policy rules, forcing a locale or language without user choice is a policy concern even if it is only used in console output.

Static analysis

No suspicious patterns detected.