Back to skill

Security audit

抖音评论分析 GuaiKei 评论洞察

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do the advertised Douyin data collection, but it needs review because it sends the API token in URL parameters and automatically saves retrieved data locally.

Review before installing. Use a limited-scope GuaiKei token if possible, assume search terms, Douyin URLs, and the token are sent to GuaiKei, and be aware the token is currently placed in URL query strings. Do not use this on shared machines or sensitive research topics unless you are prepared to manage and delete the plaintext logs under the skill directory.

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

T09 · Insecure Skill Coding Practices

Warning
Location
src/utils/request.js:94
Finding
API Token Transmitted in URL Query Strings<![CDATA[ ## Vulnerability Details **File Locations**: - `src/utils/request.js:94-121` - `src/utils/request.js:123-143` - `src/api/search.js:59-62` - `src/api/search.js:104-107` - `src/api/comment.js:38-41` - `src/api/comment.js:67-70` - `src/api/post.js:23-26` - `src/api/post.js:50-53` - `src/api/hot.js:19-21` **Vulnerability Type**: Credential exposure through URL query parameters **Risk Level**: Medium **Classification**: T09: Insecure Skill Coding Practices ### Vulnerable Code The API modules place the secret token in the request parameter object: ```js const params = { _: Date.now(), token: token, }; ``` For result polling, the token is included alongside the user-supplied query parameters: ```js const params = { _: Date.now(), token: token, keyword: keyword, sort_type: sort, publish_time: time, filter_duration: duration, content_type: content, limit: limit, }; ``` The shared request implementation serializes the complete parameter object into the URL: ```js async function postJson(path, params, data) { if (!path || typeof path !== "string") { throw new SkillError("PATH_INVALID", "path 必须是非空字符串"); } if (!params || typeof params !== "object") { throw new SkillError("PARAM_INVALID", "params 必须是对象"); } if (!data || typeof data !== "object") { throw new SkillError("DATA_INVALID", "data 必须是对象"); } params.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", "Accept-Encoding": "identity", "Content-Length": Buffer.byteLength(jsonData), }, }; return await request(options, jsonData); } ``` The GET implementation uses the same unsafe construction: ```js async function getJson(path, params) { if (!path || typeof path !== "string") { throw new SkillError("PATH_INVA ...[truncated 2690 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `token` from every URL parameter object. 2. Pass the token through a dedicated authorization header, for example: ```js const options = { host: constants.BASE_URL, path: fullPath, method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", "Accept-Encoding": "identity", "Content-Length": Buffer.byteLength(jsonData), }, }; ``` 3. Change `postJson`, `getJson`, and `requestApi` so authentication is handled separately from ordinary request parameters. 4. Ensure request, error, proxy, and application logs redact authorization headers and any legacy `token` query parameter. 5. Update the server API to reject credentials supplied through query strings after a controlled migration period. 6. Rotate tokens that have previously been sent by affected versions because they may already exist in retained infrastructure logs. 7. Add automated tests that assert generated request paths never contain `token`, `api_key`, or other credential fields. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
src/utils/log.js:5
Finding
Automatic Plaintext Persistence of Complete Retrieved Data Sets<![CDATA[ ## Vulnerability Details **File Locations**: - `src/utils/log.js:5-40` - `src/douyin/search-cli.js:258-261` - `src/douyin/post-cli.js:160-163` - `src/douyin/comment-cli.js:159-162` **Vulnerability Type**: Insecure local storage of retrieved data **Risk Level**: Low to Medium **Classification**: T09: Insecure Skill Coding Practices ### Vulnerable Code Successful comment retrieval automatically writes the complete output to disk: ```js await log.taskWrite( `${startTime}_${url}_comment.json`, JSON.stringify(finalOutput, null, 2), ); ``` Search results are persisted in the same way: ```js await log.taskWrite( `${startTime}_${keyword}_${sort}_${time}_${duration}_${content}_search.json`, JSON.stringify(finalOutput, null, 2), ); ``` The storage function creates a project-local `logs` directory and writes plaintext files without an explicit restrictive file mode: ```js async function taskWrite(filename, content) { if (!filename || typeof filename !== "string") { utils.printError("日志文件名必须是非空字符串"); return; } if (!content || typeof content !== "string") { utils.printError("日志内容必须是非空字符串"); return; } let safeFilename = filename .replace(/[\\/:*?"<>|]/g, "_") .replace(/\.\.+/g, "_") .replace(/^\.+|\.+$/g, ""); if (safeFilename.length > 200) { safeFilename = safeFilename.slice(0, 200); } if (!safeFilename) { safeFilename = `log_${Date.now()}`; } const outputFilename = path.join( path.dirname(__filename), "..", "..", "logs", safeFilename, ); try { await fs.promises.mkdir(path.dirname(outputFilename), { recursive: true }); await fs.promises.writeFile(outputFilename, content); utils.printSuccess(` → 已保存到 ${outputFilename}`); } catch (error) { utils.printError(`日志写入失败: ${error.message}`); } } ``` ### Technical Analysis Search, post, and comment commands unconditionally persist successful `finalOutput` objects. Depending on the operation, these JSON f ...[truncated 2674 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Stop writing result files by default. 2. Require explicit user intent through an option such as `--output <path>` or `--save`. 3. If local storage is enabled, create files with restrictive permissions: ```js await fs.promises.writeFile(outputFilename, content, { encoding: "utf8", mode: 0o600, flag: "wx", }); ``` 4. Create the `logs` directory with restrictive permissions such as `0o700`. 5. Avoid placing raw search terms, user identifiers, or content URLs in filenames. 6. Add configurable retention and a cleanup command or automatic expiration mechanism. 7. Document exactly which fields are stored, where they are stored, how long they remain, and how users can disable or remove them. 8. Add `logs/` to `.gitignore` and exclude it from packaging, CI artifacts, and backups unless explicitly required. 9. Consider optional encryption when users intentionally retain sensitive result sets. 10. Minimize stored content by excluding unnecessary request metadata and public-user identifiers where they are not required. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (41)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
声明描述的是一个面向抖音平台的数据采集与分析技能,核心能力应涉及网络请求、抖音资源标识处理、评论/作品/热榜数据访问或分析。而提供的代码片段仅是独立的通用命令行参数解析与帮助文本生成模块,功能范围局限于本地参数校验和 schema 驱动的帮助输出。虽然这类工具函数可能作为更大系统的辅助组件存在,但就该代码片段本身而言,其实际行为与声明的主要用途明显不一致,属于材料性不匹配。

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
声明描述的是面向抖音的数据采集与分析能力,但提供的代码并未展示任何与抖音搜索、热榜、博主作品抓取或评论分析相关的逻辑,也没有网络请求、API 调用、数据解析等行为。相反,这段代码的实际功能只是本地日志落盘,属于通用辅助工具。虽然日志功能可作为支持性实现细节存在,但就该代码片段本身而言,其行为与声明的业务能力不一致,且体现了未在描述中提及的本地文件写入能力。

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents a full-featured DouYin analytics skill with multiple data retrieval and analysis capabilities. However, the supplied code chunk contains only a small utility that accesses the local filesystem to read package.json and return the package name. This behavior does not implement or directly support the stated DouYin-specific capabilities in any visible way. While utility code can be a supporting detail, this chunk alone is unrelated to the declared primary purpose and instead performs local package metadata access, so the description is not accurately represented by the supplied code chunk.

Credential Access

High
Category
Privilege Escalation
Content
- 技能重命名为“douyin-search-keyword”。
- 在SKILL.md中添加了openclaw元数据、使用帮助、许可证、标签和示例,以实现更好的集成与文档化。
- 移除了两个本地文件(.env 和 scripts/last-search.json),以优化代码结构并提升安全性。
- 文档现已更加简洁且以用户为中心,重点在于提供清晰的使用说明和数据字段解释。
- 突出技能特性、合规要点及技术流程。
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

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
86% confidence
Finding
The trigger phrases and use cases are broad enough to match underspecified requests like generic marketing analysis or trend research, which can cause the agent to invoke this skill prematurely with ambiguous user intent. In practice this can lead to unnecessary third-party data disclosure, inappropriate routing, or collection of social-media data when the user did not clearly request DouYin-specific retrieval.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README explicitly states that scraped Douyin data, including comments and account-related outputs, are automatically exported to local log files. Because comments and account identifiers can contain personal data or sensitive business intelligence, silent persistence without a clear privacy warning, retention guidance, access controls, or redaction recommendations increases the risk of unintended disclosure on shared machines, repos, or backups.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This markdown file presents all usage instructions, parameters, and examples exclusively in Chinese. Under the policy rule for natural-language violations, forcing a specific language without user opt-in or documented justification is a reportable issue.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
This code sends the provided token and video URL to an external API via requestApi, but the file contains no confirmation prompt, logging, or explicit warning comment disclosing that user-supplied data is being transmitted. For code files, network calls that transmit user or system data should have some visible disclosure unless clearly covered elsewhere.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The GET request includes the token, URL, and limit as request parameters to a remote endpoint, but this file provides no user-facing disclosure or warning about that transmission. Because this involves sending potentially sensitive operational data over the network, some visible notice is expected in code unless documented elsewhere.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The CLI persists fetched Douyin comment results to a local JSON file automatically, which can expose potentially sensitive or regulated data such as user comments, usernames, and engagement metadata to other local users, backups, or downstream processes. In this skill’s context, the feature is specifically designed to collect and analyze social media comments at scale, so silent local retention increases privacy and data-handling risk even if the source data is public.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The CLI persists the full retrieved post results to a local JSON file via `log.taskWrite(...)` after successful execution, but there is no clear user-facing warning, consent, retention control, or opt-out. Because this skill processes Douyin post and comment analytics data, local persistence can unintentionally store potentially sensitive operational data, URLs, content metadata, and analysis outputs on disk where other local users, backup systems, or later processes may access it.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This code emits user-visible error text in Chinese, which imposes a specific language on users without any opt-in or documented regional limitation. Under the language/locale policy, hard-coding a single language can be a natural-language policy violation when no choice is provided.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The success and error messages shown to the user are fixed to Chinese, with no indication that users can select a preferred language or that the skill is region-specific. This creates a locale policy issue because the skill enforces one language by default.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
Multiple user-facing error strings in this file are written only in Chinese, such as the request failure messages, without offering a language choice or noting that the skill is Chinese-only. This creates a locale/language policy issue because the skill forces a specific language on users regardless of preference.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The AuthError message is presented only in Chinese and directs users to contact a WeChat number, with no user opt-in to that language or locale. This is a natural-language policy violation because the file enforces a single language for a key user-facing recovery path.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This file contains natural-language comments and error/output strings exclusively in Chinese, which effectively forces a specific language for users and maintainers. Under the policy, language constraints should be optional or clearly justified as region-specific.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The natural-language instructions, triggers, and usage guidance are presented entirely in Chinese, which effectively imposes a language expectation for use and routing. The file does not state that the skill is China-region-specific nor offer users a language/locale choice, so this can conflict with organizational language/locale policy requirements.

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
This JSON schema contains user-facing title and description fields entirely in Chinese, which can impose a specific language on users without any opt-in or indication that the skill is intended only for a Chinese-speaking or region-specific context. The policy specifically calls for flagging language or locale constraints that are forced without user choice or clear justification.

Natural-Language Policy Violations

Low
Confidence
83% confidence
Finding
The title and field descriptions are entirely in Chinese, which can amount to a language/locale constraint in natural-language content. The file does not document that this schema is intentionally limited to Chinese-speaking users or a China-specific workflow, nor does it offer any language choice.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The schema title and description are written only in Chinese, which imposes a specific language in natural-language metadata without offering an alternative or documenting that the schema is intentionally region-specific. This matches the policy category for language/locale constraints that are not opt-in or justified in the file.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The title and property descriptions are written only in Chinese, which implies a fixed language choice in the skill's user-facing schema metadata. Because the file does not document that the skill is China-specific or offer any language/locale opt-in, this may violate the policy against forcing a specific language without user choice.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
This JSON schema uses Chinese-only natural-language titles and descriptions throughout, including the top-level title/description and property descriptions. Because SQP-3 applies to all file types and covers language or locale policy violations, this can be a policy issue when the skill is expected to be locale-neutral or user-selectable.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
This manifest-style JSON file uses Chinese-only title and description fields for the schema and its primary parameter, which can constitute a language/locale policy issue when no opt-in or scope limitation is documented. The file does not indicate that the skill is region-specific or that Chinese is an intentional, justified locale constraint.

Natural-Language Policy Violations

Low
Confidence
90% confidence
Finding
The schema title and descriptions are entirely in Chinese, which imposes a specific language/locale in natural-language metadata. There is no indication that the skill is region-specific or that users can opt into another language, so this may violate language/locale policy requirements.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
SKILL.md:24