Back to skill

Security audit

快手评论分析

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Kuaishou comment-reporting purpose, but its report generation and documented shell usage create real local security risks.

Review this skill before installing. It needs a Redfox API key, sends requested Kuaishou opus IDs to Redfox, and writes local HTML reports containing comment data. Avoid opening generated reports from untrusted comment sources until avatar URLs and analysis summaries are sanitized, auto-open behavior is made opt-in, and JSON is passed through stdin or files rather than embedded in shell commands.

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/kuaishou_comment_search.py:137
Finding
Stored HTML and Script Injection in Generated Reports<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/kuaishou_comment_search.py:137-148` - `scripts/consolidate_report.py:35-46` - `scripts/backfill_html.py:38-44` - `scripts/consolidate_report.py:174-181` - `assets/report_template.html:439-458` - `assets/consolidate_report_template.html:378-397` **Vulnerability Type**: Stored HTML injection and cross-site scripting **Risk Level**: High ### Vulnerable Code The avatar URL returned by the API or supplied through page JSON is inserted into an HTML attribute without escaping or URL validation: ```python avatar = c.get("user_avatar", "") or "" name = escape_html(c.get("user_name", "")) content = escape_html(c.get("content", "")) like = c.get("like_count", 0) or 0 reply = c.get("reply_count", 0) or 0 time_str = (c.get("create_time", "") or "")[5:16] ip = escape_html(c.get("ip_location", "")) row = ( f'<tr{row_class}>' f'<td>' f'<div class="user-cell">' f'<img src="{avatar}" class="user-avatar" alt="" onerror="this.style.display=\'none\'" referrerpolicy="no-referrer">' f'<span class="user-name">{name}{pin_badge}</span>' f'</div>' f'</td>' ) ``` AI-generated analysis summaries are also inserted as raw HTML: ```python summary_map = { "{{SUMMARY_POSITIVE}}": analysis.get("positive_summary", ""), "{{SUMMARY_NEGATIVE}}": analysis.get("negative_summary", ""), "{{SUMMARY_DEMAND}}": analysis.get("demand_summary", ""), "{{SUMMARY_COMPETITOR}}": analysis.get("competitor_summary", ""), } for key, val in summary_map.items(): html = html.replace(key, val) ``` The consolidated report generator uses the same unsafe pattern: ```python "{{POSITIVE_RATIO}}": str(analysis.get("positive_ratio", "--")), "{{NEGATIVE_RATIO}}": str(analysis.get("negative_ratio", "--")), "{{DEMAND_RATIO}}": str(analysis.get("demand_ratio", "--")), "{{COMPETITOR_RATIO}}": str(analysis.get("competitor_ratio", "--")), "{{SUMMARY_POSITIVE}}": analysis.get("positive_summary", ""), "{{SUMMARY_NEG ...[truncated 3101 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply contextual HTML attribute escaping to avatar URLs using `html.escape(value, quote=True)`. 2. Parse avatar URLs with `urllib.parse.urlparse` and permit only `https` URLs from explicitly approved hosts. 3. Reject URLs containing credentials, control characters, unsupported schemes, or malformed hostnames. 4. Replace raw HTML summaries with structured arrays of plain-text bullet points and generate `<ul>` and `<li>` elements internally. 5. If formatted summary HTML must be supported, sanitize it with a strict allowlist that permits only necessary elements and no attributes. 6. Validate ratio fields as bounded numeric values rather than inserting arbitrary strings. 7. Add a restrictive Content Security Policy that blocks inline event handlers, unapproved scripts, and unapproved network destinations. 8. Add tests containing quotation marks, event handlers, `<script>` elements, SVG payloads, and dangerous URL schemes. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:156
Finding
Shell Command Injection Through Documented JSON Interpolation<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:143` - `SKILL.md:156-159` **Vulnerability Type**: Shell command injection **Risk Level**: High ### Vulnerable Instructions The Skill instructs the Agent to place dynamically generated analysis JSON inside a single-quoted shell argument: ```bash python3 ~/.agents/skills/kuaishou-comment/scripts/backfill_html.py "<html_path>" --analysis-json '<分析JSON>' open "<html_path>" ``` It applies the same pattern to collected comment pages: ```bash python3 ~/.agents/skills/kuaishou-comment/scripts/consolidate_report.py "<opusId>" \ --pages-json '[{"page":1,"total":31,"comments":[...]},{"page":2,"total":20,"comments":[...]}]' \ --analysis-json '<累计分析JSON>' open "<html_path>" ``` ### Technical Analysis JSON encoding does not escape apostrophes because apostrophes have no special meaning in JSON. They do, however, terminate single-quoted strings in POSIX-compatible shells. The `--pages-json` argument may include public comment content controlled by Kuaishou users. The `--analysis-json` argument can include representative quotes copied from those comments. If the Agent constructs and executes the documented command through a shell, a crafted apostrophe can terminate the quoted JSON and introduce shell operators and additional commands. For example, a comment containing content structurally equivalent to the following can break the documented quoting boundary: ```text '; attacker_command; # ``` The Python scripts themselves use `argparse` and do not directly invoke a shell for these JSON arguments. The vulnerability arises from the Skill's operational instructions directing the Agent to interpolate untrusted data into a shell command. ### Attack Path 1. An attacker posts a Kuaishou comment containing an apostrophe followed by shell metacharacters and command text. 2. The Skill fetches the comment and includes it in collected page JSON or an AI-generated summary. 3. The Agent follows `SKILL.md` an ...[truncated 997 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Prohibit interpolation of comments, summaries, cursors, and JSON documents into shell command strings. 2. Pass JSON through standard input using a structured process invocation that does not invoke a shell. 3. When invoking Python programmatically, use an argument array with `shell=False`. 4. Alternatively, write JSON to a securely created temporary file with restrictive permissions and pass only the file path. 5. Add explicit file-based options such as `--pages-file` and `--analysis-file`. 6. Validate `opus_id`, cursor, page number, and output paths before use. 7. Update `SKILL.md` with a warning that JSON must never be embedded into a shell command. 8. Add regression tests using comments containing apostrophes, command substitutions, semicolons, newlines, and shell redirection characters. ]]>

other

Note
Location
assets/report_template.html:9
Finding
Generated Offline Reports Perform Undisclosed External Requests<![CDATA[ ## Vulnerability Details **File Locations**: - `assets/report_template.html:9-11` - `assets/consolidate_report_template.html:9-11` - `scripts/kuaishou_comment_search.py:137-148` - `scripts/consolidate_report.py:35-46` - `scripts/consolidate_report.py:267` **Vulnerability Type**: Undisclosed external resource loading and report-view tracking **Risk Level**: Low ### Vulnerable Code Both report templates connect to Google-hosted font services: ```html <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet"> ``` Reports also embed remote avatar URLs: ```python avatar = c.get("user_avatar", "") or "" row = ( f'<tr{row_class}>' f'<td>' f'<div class="user-cell">' f'<img src="{avatar}" class="user-avatar" alt="" onerror="this.style.display=\'none\'" referrerpolicy="no-referrer">' f'<span class="user-name">{name}{pin_badge}</span>' f'</div>' f'</td>' ) ``` The consolidated report is opened automatically: ```python subprocess.run(["open", html_path]) ``` ### Technical Analysis The documentation describes generated reports as suitable for offline access. However, opening a report initiates connections to Google Fonts and every remote avatar host represented in the report. The `referrerpolicy="no-referrer"` attribute reduces referrer disclosure for avatar requests, but it does not prevent destination servers from receiving the viewer's public IP address, request time, user-agent metadata, and other connection-level information. Remote avatars are not required for the declared comment-analysis functionality. The Skill instructions also state that the conversational table should not display avatars, making their inclusion in generated reports an avoidable network capability. Automatic opening of consolidated repo ...[truncated 1027 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove Google Fonts and use system font stacks, or bundle required fonts locally. 2. Omit user avatars from generated reports unless they are necessary and explicitly requested. 3. If avatars are required, download them only with informed user consent, validate their origin and media type, and embed vetted local copies. 4. Disable automatic report opening and return the report path so the user can decide whether to open it. 5. Add a Content Security Policy that blocks remote resources by default. 6. Clearly disclose any remaining external connections in the documentation. 7. Update the “offline access” description unless reports are made completely self-contained. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
声明描述的是一个面向快手评论抓取与分析的完整工具,而代码片段实际只是报告后处理组件,用于将已存在的分析结果填入 HTML 模板。虽然它与“生成 HTML 报告”这一子功能相关,但缺少声明中的核心能力:评论抓取、链接处理、分页展示和分析执行。因此代码实际行为与技能整体声明存在明显不一致,属于功能大幅缩水/主目的不同的情况。

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
该代码的核心功能与声明部分一致地覆盖了“获取快手一级评论数据”“分页所需 cursor/next_cursor 信息”“生成 HTML 报告”等能力,因此整体领域和主要用途基本相关。但声明中明确承诺了评论情感分析/舆情分类(积极、负面、需求、竞品),而代码仅是调用外部接口获取评论列表、格式化字段并渲染 HTML,没有任何 NLP、分类、标签统计或分析结果输出。这属于重要能力缺失。此外,声明称输入作品链接即可使用,而脚本参数实际要求的是 opusId,未见链接解析逻辑。故描述与实际行为存在实质性不一致。

Hidden Instructions

High
Category
Prompt Injection
Content
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>快手评论分析 - {{OPUS_ID}}</title>

<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>快手评论分析 - {{OPUS_ID}}</title>

<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The skill advertises activation from broad natural-language inputs such as any Kuaishou link or opusId, without clearly constraining when the agent should invoke the skill. In an agentic environment, this can cause over-eager or unintended tool execution on conversational text, potentially sending user-supplied links or identifiers to an external service without sufficiently explicit user intent.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README emphasizes collecting comment data, including fields like user identifiers and IP locality, and generating local HTML reports, but does not clearly warn about privacy, retention, sharing, or the security implications of opening generated files. In this context, the skill handles potentially sensitive third-party data, so weak disclosure increases the risk of inappropriate collection, redistribution, or unsafe file handling.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The activation guidance is overly broad because it says any natural-language message containing a Kuaishou link or opusId can trigger the skill, without requiring explicit user intent to fetch comments. This can cause accidental invocation on unrelated messages containing links/IDs and may lead to unintended external requests or processing of third-party content.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill instructs the agent to use shell, network, file read/write, and environment-based secrets, but it declares no explicit tool scope or permissions boundary. In an agent runtime, this increases the chance of unintended command execution, uncontrolled file output, or secret exposure because the platform cannot constrain the skill to only the minimum required capabilities.

Vague Triggers

Medium
Confidence
91% confidence
Finding
Overly broad trigger phrases can cause accidental invocation in unrelated conversations, which is risky for a skill that performs network access, writes files, and opens generated HTML. Unintended activation may fetch third-party content or generate local artifacts without the user clearly intending to run this capability.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill saves comment data into HTML reports and instructs the agent to open them, but it does not clearly warn users that generated files may contain third-party content and potentially sensitive comment text. Without an explicit warning and sanitization expectations, users may unknowingly persist or open reports containing untrusted or privacy-relevant data.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This HTML template sets the document language to zh-CN and all visible labels, headings, and branding are presented only in Chinese. Under the policy, forcing a specific language without user opt-in or a documented justification is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The HTML root sets `lang="zh-CN"`, which hard-codes a specific language/locale in the generated report. In this file there is no accompanying natural-language note that the locale is optional, user-selected, or justified as a region-specific requirement.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This Python file contains natural-language docstrings, argument descriptions, and console messages entirely in Chinese, which effectively imposes a specific language on users. The file does not offer a language/locale choice or explain that the script is intentionally region-specific, so it matches the locale-policy violation criteria.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The module docstring, CLI descriptions, log messages, and generated report labels are all hard-coded in Chinese, which can force a specific language experience on users. The file does not offer localization, language selection, or justification that the skill is intentionally limited to a Chinese-speaking or region-specific context.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
For a comment analysis/report generation tool, reading input, producing analysis, and writing HTML are expected. Importing `subprocess` and using it at L267 to execute the platform `open` command introduces process-spawning capability that is not necessary to analyze comments or generate the report itself.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The script writes a complete HTML report containing comment content, usernames, avatars, timestamps, and IP location data to a predictable local directory without explicit warning or consent. This creates a privacy and data-retention risk because potentially sensitive third-party data persists on disk and may be accessible to other local users, backup systems, or later processes.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
Automatically opening the generated report removes the user's chance to inspect or decline rendering of a file built from untrusted external comment data. In this code, avatar URLs are inserted into img src attributes without escaping or scheme validation, so immediate browser rendering increases the practical exposure to malicious or tracking content.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(json.dumps({"html_path": html_path}, ensure_ascii=False))

    # 自动在浏览器中打开
    subprocess.run(["open", html_path])


if __name__ == "__main__":
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest says the skill supports comment sentiment analysis across categories like 积极/负面/需求/竞品 and analyzes 舆情, but this script only retrieves first-level comments from an API, normalizes fields, and optionally renders them into an HTML table. No code computes sentiment labels, aggregates opinion insights, or classifies comments into the described categories.

Vague Triggers

Low
Confidence
84% confidence
Finding
Using a vague conversational trigger like 'Next page' for pagination is prone to accidental activation because it is a common phrase that may appear in ordinary dialogue. In a multi-tool or multi-turn agent setting, this can advance stateful data retrieval unexpectedly, leading to unintended external requests or confusing state changes.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The instructions prescribe a fixed Chinese response phrase for missing input and the document consistently mandates Chinese-language outputs without indicating that the user may choose another language. This can violate language/locale policy when no opt-in or justified locale restriction is stated.

Description-Behavior Mismatch

Low
Confidence
91% confidence
Finding
The script does more than generate a report: it immediately launches the produced HTML in the local browser without an explicit opt-in. In this skill, the HTML embeds user-controlled comment fields and unescaped avatar URLs, so auto-opening increases the chance that unsafe HTML content is rendered immediately on the analyst's machine.

Missing User Warnings

Low
Confidence
89% confidence
Finding
This code creates a directory and writes a report file to the user's filesystem, defaulting to ~/Downloads/QoderReports. Although command-line flags control the behavior and stderr logs announce the generated path after the write, there is no confirmation prompt and no clear pre-execution warning in the module docstring about automatic local file creation unless --no-html is used.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/kuaishou_comment_search.py:27