Back to skill

Security audit

guaikei-v2t

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it can fetch arbitrary URLs and upload the resulting content to a server-chosen HTTPS destination broader than its documentation discloses.

Review before installing. Only use this skill with media you are willing to send to a third-party cloud service, avoid attacker-supplied or internal/private URLs, and prefer local transcription for confidential content until URL allowlisting, private-network blocking, download limits, and upload-host disclosure are added.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/utils/validator.js:3
Finding
Unrestricted URL Fetching Enables Internal Resource Access and Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-9`, `scripts/video2text/index.js:95-134`, `scripts/utils/download.js:479-493` **Vulnerability Type**: Server-Side Request Forgery (SSRF) with subsequent data upload **Risk Level**: High ### Vulnerable Code `scripts/utils/validator.js:3-9`: ```js function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` `scripts/video2text/index.js:95-134`: ```js 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); } // 下载文件缺少扩展名时统一补 .mp4,便于服务端识别视频类型 if (tempFilePath.indexOf(".") === -1) { try { fs.renameSync(tempFilePath, tempFilePath + ".mp4"); tempFilePath += ".mp4"; } catch (renameError) { utils.printWarn("文件重命名失败: " + renameError.message); } } utils.printInfo("网络视频已下载到本地: " + tempFilePath); file = tempFilePath; } catch (error) { utils.printError("下载失败: " + (error.message || String(error))); process.exit(1); } } else if (!validator.isFilePath(file)) { utils.printError("无效的文件路径或URL"); process.exit(1); } if (!fs.existsSync(file)) { utils.printError("文件不存在: " + file); process.exit(1); } ``` `scripts/utils/download.js:479-493`: ```js 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.e ...[truncated 2562 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only HTTPS URLs unless plain HTTP is explicitly required and approved. 2. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 ranges. 3. Explicitly block cloud metadata addresses, including `169.254.169.254` and platform-specific metadata hostnames. 4. Repeat full validation after every redirect. 5. Verify the actual socket address after connection to prevent DNS rebinding and time-of-check/time-of-use bypasses. 6. Normalize and validate IPv4-mapped IPv6 addresses, integer IP representations, and alternate encodings. 7. Consider an allowlist of supported public video platforms and content-delivery domains. 8. Require explicit user confirmation before uploading content retrieved from a URL outside the expected domain set. 9. Add tests covering direct private addresses, redirect-based SSRF, DNS rebinding, IPv6 local addresses, and metadata endpoints. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/download.js:32
Finding
Missing Download Size and Timeout Limits Permit Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/download.js:32-47`, `scripts/utils/download.js:464-475`, `scripts/utils/download.js:526-576`, `scripts/utils/helper.js:28-36` **Vulnerability Type**: Uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code `scripts/utils/download.js:32-47`: ```js this.__defaultOpts = { body: null, retry: false, method: "GET", headers: {}, fileName: "", timeout: -1, metadata: null, override: false, forceResume: false, removeOnStop: true, removeOnFail: true, maxRedirects: 10, progressThrottle: 1000, httpRequestOptions: {}, httpsRequestOptions: {}, resumeOnIncomplete: true, resumeIfFileExists: false, resumeOnIncompleteMaxRetry: 5, }; ``` `scripts/utils/download.js:464-475`: ```js 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(); } ``` `scripts/utils/download.js:526-576`: ```js 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, {}); this.emit("download", { fileName: this. ...[truncated 2679 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a maximum permitted download size appropriate for supported video workloads. 2. Reject responses whose declared `Content-Length` exceeds that limit. 3. Independently count streamed bytes and abort immediately when the actual limit is exceeded. 4. Configure separate DNS, connection, response-header, idle-read, and total-operation timeouts. 5. Destroy the HTTP request and response streams when any limit is exceeded. 6. Delete partial files on timeout, failure, cancellation, and size-limit violations. 7. Apply an aggregate quota to the temporary directory so parallel executions cannot collectively exhaust storage. 8. Limit retries and ensure retries do not retain duplicate partial content. 9. Validate available disk space before downloading and before uploading. 10. Add automated tests for chunked infinite responses, understated `Content-Length`, slow responses, and oversized files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/utils/upload.js:11
Finding
Server-Controlled Upload Destination Is Not Restricted to Trusted Storage Hosts<![CDATA[ ## Vulnerability Details **File Location**: `scripts/video2text/index.js:135-151`, `scripts/utils/upload.js:11-40`, `SKILL.md:91-95` **Vulnerability Type**: Unrestricted external upload destination and inaccurate network-scope declaration **Risk Level**: Medium ### Vulnerable Code `scripts/video2text/index.js:135-151`: ```js 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"); if (presignedUrl.url.indexOf("?") === -1) { throw new Error("预签名URL格式错误,请反馈给开发者"); } const url = presignedUrl.url.substring(0, presignedUrl.url.indexOf("?")); const task = await video.getVideoId(tokenValue, url); ``` `scripts/utils/upload.js:11-40`: ```js 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 } ...[truncated 2296 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Maintain an explicit allowlist of authorized object-storage hostnames or narrowly scoped domain suffixes. 2. Reject unexpected ports, URL credentials, IP-literal destinations, ambiguous hostnames, and nonstandard URL forms. 3. Resolve and validate destination addresses so approved hostnames cannot resolve to loopback, private, or link-local networks. 4. Validate server-provided headers against an allowlist and reject sensitive or unrelated header names. 5. Bind the expected storage host or provider to trusted client configuration rather than accepting an unrestricted server response. 6. Where feasible, verify a signed response containing the approved hostname, object key, expiration, and upload method. 7. Update `SKILL.md` and `README.md` to identify every legitimate API, storage, and model-processing recipient. 8. Clearly disclose retention, deletion, processing, and cross-border transfer behavior rather than relying solely on unverified assurances. 9. Log the normalized upload hostname for user visibility without logging signed query parameters or credentials. 10. Add tests confirming that unauthorized HTTPS hosts, IP literals, private addresses, and malicious headers are rejected. ]]>
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 (24)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A skill that mainly performs token checks, pause controls, or promotional messaging while claiming to transcribe and analyze video misleads users and orchestration systems about both utility and risk. That can cause improper routing of user data, wasted trust, and unnecessary exposure of secrets such as API tokens without delivering the declared function.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
A skill that mainly performs token checks, pause controls, or promotional messaging while claiming to transcribe and analyze video misleads users and orchestration systems about both utility and risk. That can cause improper routing of user data, wasted trust, and unnecessary exposure of secrets such as API tokens without delivering the declared function.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
A skill that mainly performs token checks, pause controls, or promotional messaging while claiming to transcribe and analyze video misleads users and orchestration systems about both utility and risk. That can cause improper routing of user data, wasted trust, and unnecessary exposure of secrets such as API tokens without delivering the declared function.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A skill that mainly performs token checks, pause controls, or promotional messaging while claiming to transcribe and analyze video misleads users and orchestration systems about both utility and risk. That can cause improper routing of user data, wasted trust, and unnecessary exposure of secrets such as API tokens without delivering the declared function.

Missing User Warnings

High
Confidence
96% confidence
Finding
The downloader copies URL-embedded username/password into the HTTP auth field, causing credentials present in a supplied URL to be transmitted automatically. In this skill context, URLs may come from user-provided third-party video links, so an attacker could induce authenticated requests to internal or external services, leaking secrets or accessing resources with unintended credentials.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The README defines broad natural-language-to-command conversion rules such as treating any detected link or file path as a `--file` argument and any analysis request as `--prompt`, without clear trigger boundaries, confirmation steps, or input validation guidance. In an agent setting, this can cause unintended execution against attacker-supplied URLs, reuse of prior task IDs, or overly permissive prompt forwarding, which may lead to unintended data processing or SSRF-like fetch behavior depending on the implementation.

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
74% confidence
Finding
The skill declares access to the sensitive environment variable `GUAIKEI_API_TOKEN` in metadata but does not define explicit tool scope such as `permissions` or `allowed-tools`. That weakens least-privilege guarantees and makes it harder for the host to constrain what the skill may access, especially given the skill also claims networked cloud processing of user-supplied media.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The trigger examples are broad enough to overlap with common summarization or content-analysis requests, which can cause an agent to invoke this external, token-bearing, networked skill when a safer local capability would suffice. In context, that increases the chance of unnecessary third-party sharing of user-provided links, files, or content.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The guidance tells the agent to prioritize this skill for wide intent categories such as summarization, rewriting, and analysis, without requiring strong evidence that the input is actually a supported video task. That expands the skill's effective authority and can route unrelated user content to a third-party service under an overly permissive invocation policy.

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
93% confidence
Finding
This file's docstrings, validation errors, and operation labels are entirely in Chinese, which indicates a fixed language choice in user-visible text. Under the policy, forcing a specific language without user opt-in or documented justification is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This utility emits all user-facing strings in Chinese, including error messages and help text. That hard-codes a single language for all users and matches the policy category for language/locale constraints without an explicit opt-in or documented region-specific justification.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This JavaScript file contains natural-language comments and user-facing log/error strings only in Chinese, with no indication that the skill is region-specific or that users can opt into the locale. Under the policy, forcing a specific language without user choice or justification is a natural-language policy violation.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This utility performs outbound HTTP/HTTPS requests and follows redirects, potentially sending request headers and URL-derived data to multiple remote endpoints, but the code does not provide any visible warning or explanatory comment about that behavior. Because network transmission is safety-relevant, especially when headers or credentials may be included, some disclosure is expected.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This code creates and appends to files on disk, and elsewhere in the class it also deletes files on stop/failure, but there is no confirmation prompt, print/log statement, or explanatory comment/docstring warning users about these filesystem side effects. For a reusable downloader utility, these are safety-relevant operations that can affect user data and should be disclosed clearly.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Multiple thrown error messages are written in Chinese, which forces a specific language for user-visible output. The file does not offer localization, user language selection, or any justification that the skill is intentionally limited to a Chinese-speaking or region-specific audience.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Authentication, timeout, and network failure messages are user-facing and all hard-coded in Chinese. This enforces a specific language in operational error handling without giving users a choice or documenting a locale restriction.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code sends arbitrary JSON data over HTTPS and includes a TOKEN header, which means user or system data may be transmitted to a remote service. Within this file there is no confirmation prompt, user-facing notice, or explicit warning comment/docstring describing that outbound network transmission and credential use occur.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
This code emits all warning and informational messages exclusively in Chinese, with no indication that the skill is region-specific or that the user can choose a different language. That creates a natural-language policy concern because the skill imposes a specific language on users without opt-in.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The entire skill documentation and usage guidance are presented only in Chinese, and no language or locale choice is offered to users. This can constitute a language policy violation when users are not given an explicit opt-in or alternative locale.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The natural-language comment uses Chinese only ("下载文件") with no indication that the skill is region-specific or that users can choose their preferred language. This can violate a language/locale policy when skills are expected to be language-neutral or offer opt-in.

Missing User Warnings

Low
Confidence
74% confidence
Finding
The error message explicitly references GUAIKEI_API_TOKEN, indicating the skill depends on a sensitive token credential. This file lacks any nearby user-facing warning or explanatory comment that the skill uses such a credential to authenticate outbound requests.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The banner string is hard-coded in Chinese, which indicates a fixed language experience rather than offering the user a locale or language choice. The policy explicitly calls for flagging language or locale constraints when they are forced without user opt-in or documented justification.

Static analysis

No suspicious patterns detected.