Back to skill

Security audit

guaikei-extract-video-text

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its advertised cloud video-to-text purpose, but it can fetch and upload overly broad URLs and local files without enough scoping or confirmation.

Install only if you are comfortable sending video content, prompts, task identifiers, filenames, and an API token to the provider's cloud service. Avoid passing sensitive local paths, private-network URLs, localhost URLs, metadata-service URLs, or untrusted redirected links; prefer explicit user-approved media files and public HTTPS video sources.

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:12
Finding
Arbitrary Local File Upload Through Unrestricted File Input<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:12-19`, `scripts/video2text/index.js:123-146`, `scripts/utils/upload.js:10-43` **Vulnerability Type**: Unrestricted local file access and external upload **Risk Level**: High ### Vulnerable Code ```js // scripts/utils/validator.js:12-19 function isFilePath(path) { try { const stats = fs.statSync(path); return stats.isFile(); } catch (_) { return false; } } ``` ```js // scripts/video2text/index.js:123-146 if (!fs.existsSync(file)) { utils.printError("文件不存在: " + file); process.exit(1); } try { 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"); ``` ```js // scripts/utils/upload.js:10-43 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); const uploadHeaders = Object.assign({}, headers); 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 }, (res) => { ``` ### Technical Analysis The local-file validator only checks whether the supplied path refers to a r ...[truncated 1864 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require explicit user confirmation before uploading any local file. 2. Restrict local inputs to user-approved directories or to files explicitly attached to the current task. 3. Resolve the canonical path with `fs.realpath()` and verify that it remains under an approved root. 4. Reject symbolic links or verify both the link and final target before opening the file. 5. Allow only supported media extensions, but do not rely on extensions alone. 6. Inspect file magic bytes and compare them against an allowlist of supported video and audio formats. 7. Reject non-media MIME types and unsupported container formats. 8. Enforce a maximum file size before opening the stream. 9. Open the validated file safely and protect against validation-to-use path replacement where the threat model includes local attackers. 10. Send only a sanitized basename to the presign API rather than the complete local path. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/utils/validator.js:3
Finding
Server-Side Request Forgery and Internal-Network Data Relay<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-9`, `scripts/utils/download.js:464-490`, `scripts/video2text/index.js:96-146` **Vulnerability Type**: Unrestricted outbound URL retrieval and redirect-based SSRF **Risk Level**: High ### Vulnerable Code ```js // scripts/utils/validator.js:3-9 function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` ```js // scripts/utils/download.js:464-490 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(); } 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:96-105 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); ``` ### Technical Anal ...[truncated 2104 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prefer an explicit allowlist of supported public video-provider domains. 2. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, reserved, and documentation ranges for both IPv4 and IPv6. 3. Explicitly block common metadata destinations, including link-local metadata addresses. 4. Repeat hostname resolution and network-range validation for every redirect. 5. Reject redirects that change to a prohibited host, port, or scheme. 6. Prevent DNS rebinding by connecting only to the validated resolved address while preserving the intended TLS server name and HTTP host where necessary. 7. Permit only expected destination ports, normally 443 and, only if required, 80. 8. Apply outbound firewall or sandbox controls so the process cannot reach internal networks or metadata endpoints. 9. Avoid automatically uploading content downloaded from arbitrary URLs until its origin and media type have been validated. 10. Add automated tests covering encoded IP addresses, IPv6, mixed notation, redirects, and DNS responses that resolve to private addresses. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/helper.js:27
Finding
Unbounded Remote Downloads Can Exhaust Local Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/helper.js:27-36`, `scripts/utils/download.js:514-567` **Vulnerability Type**: Unrestricted download size and resource exhaustion **Risk Level**: Medium ### Vulnerable Code ```js // scripts/utils/helper.js:27-36 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 }, }; ``` ```js // scripts/utils/download.js:514-567 __startDownload(response, resolve, reject) { let readable = response; if (!this.__isResumed) { 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); const totalSize = this.__total ? this.__total : 0; if ( typeof this.__opts.override === "object" && this.__opts.override.skip && (this.__opts.override.skipSmaller || downloadedSize >= totalSize) ) { this.emit("skip", { totalSize: this.__total, fileName: this.__fileName, filePath: this.__filePath, downloadedSize: downloadedSize, }); this.__setState(this.__states.SKIPPED); return resolve(true); } } 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. ...[truncated 2148 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a strict maximum supported media size based on service requirements. 2. Reject responses whose declared `Content-Length` exceeds the configured limit. 3. Maintain an independent cumulative byte count and destroy the response and file stream immediately when the limit is exceeded. 4. Delete all partial files after a limit violation or transfer failure. 5. Require an allowed video or audio content type and validate file magic bytes after downloading. 6. Set an overall operation deadline in addition to socket inactivity timeouts. 7. Enforce minimum transfer-rate or maximum idle-time policies to mitigate slow streaming attacks. 8. Check available disk space or apply a dedicated filesystem quota before downloading. 9. Avoid retrying downloads after size-limit violations and other deterministic validation failures. 10. Use a uniquely created, permission-restricted temporary directory and remove downloaded content promptly after upload or failure. ]]>
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 (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill accepts arbitrary remote URLs and states it will download them to a local tmp directory, with redirect/retry/range handling. Without an explicit allowlist, scheme restrictions, and SSRF/local-address protections, this can enable fetching attacker-controlled resources or internal network endpoints, creating server-side request forgery and risky file-handling exposure. In this skill context, remote video ingestion is expected, which makes the behavior less suspicious, but it is still dangerous if input URLs are insufficiently constrained.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill accepts arbitrary remote URLs and states it will download them to a local tmp directory, with redirect/retry/range handling. Without an explicit allowlist, scheme restrictions, and SSRF/local-address protections, this can enable fetching attacker-controlled resources or internal network endpoints, creating server-side request forgery and risky file-handling exposure. In this skill context, remote video ingestion is expected, which makes the behavior less suspicious, but it is still dangerous if input URLs are insufficiently constrained.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The skill accepts arbitrary remote URLs and states it will download them to a local tmp directory, with redirect/retry/range handling. Without an explicit allowlist, scheme restrictions, and SSRF/local-address protections, this can enable fetching attacker-controlled resources or internal network endpoints, creating server-side request forgery and risky file-handling exposure. In this skill context, remote video ingestion is expected, which makes the behavior less suspicious, but it is still dangerous if input URLs are insufficiently constrained.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill accepts arbitrary remote URLs and states it will download them to a local tmp directory, with redirect/retry/range handling. Without an explicit allowlist, scheme restrictions, and SSRF/local-address protections, this can enable fetching attacker-controlled resources or internal network endpoints, creating server-side request forgery and risky file-handling exposure. In this skill context, remote video ingestion is expected, which makes the behavior less suspicious, but it is still dangerous if input URLs are insufficiently constrained.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Although the README mentions cloud processing and privacy claims elsewhere, it does not clearly warn at the point of use that supplied video files and links are sent to a remote cloud service for processing. This can mislead users into believing processing is local or low-risk, increasing the chance of exposing sensitive media, transcripts, or embedded personal data to an external provider without informed consent.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The README defines very broad natural-language activation rules such as any request containing a video link, local file path, or summary/rewrite intent. In an agent setting, this can cause over-triggering on ordinary conversation and may lead to unintended upload and processing of user-provided videos or URLs by a remote service without sufficiently explicit user confirmation.

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.

Whitespace Padding

Medium
Category
Prompt Injection
Content
## 6. 🧠 自然语言 → 命令 映射(AI 执行参考)

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

Vague Triggers

Medium
Confidence
91% confidence
Finding
This manifest description lists many generic scenarios and capabilities such as transcription, summaries, rewriting, meeting minutes, and content creation, but does not define what specific user requests should invoke the skill versus ordinary conversation. In a manifest file, that broad natural-language scope can create ambiguous activation and unintended invocation overlap with common requests.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The user-facing description is entirely in Chinese and explicitly references generating '中英翻译' as one of the outputs, but it does not indicate that users may choose their preferred interaction language or output locale. This can be a natural-language locale policy issue if the skill defaults to a specific language without opt-in or documented justification.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The file contains user-visible error messages and operation labels exclusively in Chinese, such as parameter validation errors and request descriptors. This can violate language/locale policy when the skill forces a specific language without offering user opt-in or documenting a justified locale restriction.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This helper constructs an HTTPS POST request, serializes arbitrary input data, and sends it along with a TOKEN header to a remote host. The file contains no confirmation prompt, user-facing warning, or explanatory comment disclosing that user/system data and credentials may be transmitted off-host.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
All user-visible warning and status strings in this flow are written in Chinese, including operational guidance and promotional text, with no indication that the user can select another language. This can violate language/locale policy where skills must not impose a specific language without user opt-in.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The comment at L007-L009 makes strong operational promises: no leakage, no secondary use, and automatic deletion after processing. However, the implementation in this file only performs an HTTPS PUT to a provided presigned URL and contains no logic for deletion, retention control, or usage restriction enforcement.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
The banner text is hardcoded in Chinese, which indicates the skill presents itself in a specific language without any visible opt-in or locale selection. Under the policy, language-specific behavior should either offer user choice or clearly document a justified locale restriction.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
User-facing descriptions, help text, and examples are presented only in Chinese, which imposes a specific language on users without any opt-in or alternative. The policy explicitly calls out language or locale constraints as violations unless the skill offers a choice or clearly documents a justified regional limitation.

Missing User Warnings

Low
Confidence
80% confidence
Finding
This code sends user-supplied filename data and an API token to a remote endpoint to obtain upload credentials, but there is no confirmation prompt or user-facing disclosure in the file itself. Similar undisclosed transmissions continue in later functions for uploaded video URLs and prompts, which may affect user privacy if callers are unaware that data is sent to an external API.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This file embeds user-facing natural-language strings in Chinese, beginning with the top-level description and continuing throughout errors and help output. Under the policy, forcing a specific language without user opt-in can be a locale-policy violation unless the constraint is explicitly justified.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
The thrown errors, warnings, usage text, and examples are all presented only in Chinese, with no indication that users can choose another language. That creates a natural-language policy concern because the skill appears to enforce a single locale for all users.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This code includes all user-visible descriptions and runtime messages in Chinese, including the docstring and printed informational/error text. Under the policy, forcing a specific language without offering user choice or documenting a justified locale restriction is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
Multiple user-visible error messages are written only in Chinese, including operational guidance and support contact text. That forces a specific language/locale on users without any opt-in or explanation, which fits the language-policy violation category.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
This JavaScript file uses Chinese-only natural-language documentation and runtime messages throughout, including the function docstring and error/progress output. Under the language/locale policy rule, forcing a specific language without user opt-in can be a policy violation when no alternative locale or choice is provided.

Static analysis

No suspicious patterns detected.