Back to skill

Security audit

Fetch Wechat Article

Security checks for vulnerabilities and agentic risk

Overview

This WeChat article downloader is not malicious, but it needs review because it can browse arbitrary URLs with a weakened browser sandbox and writes unescaped HTML output.

Review before installing. Use this only in an isolated environment, pass only intended WeChat article URLs, and avoid opening generated HTML from untrusted pages until the tool adds strict mp.weixin.qq.com URL validation, removes the default browser --no-sandbox flag, and safely escapes or sanitizes HTML output.

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/fetch_wechat_article.py:336
Finding

Unrestricted URL Navigation Enables Server-Side Request Forgery

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fetch_wechat_article.py:300
Finding

Browser Sandbox Is Unconditionally Disabled for Remote Content

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_wechat_article.py:103
Finding

Untrusted Article Data Is Written into Executable HTML Without Safe Escaping

Content
View full analysis
]+>', '', text) # HTML 实体解码(尤其是 & → &,影响图片 URL) text = ( text.replace('&', '&') .replace('<', '<') .replace('>', '>') .replace('"', '"') .replace(''', "'") .replace(' ', ' ') ) ``` ```python if line.startswith('# '): html_body += f"

{line[2:]}

\n" elif line.startswith('## '): html_body += f"

{line[3:]}

\n" elif line.startswith('- '): html_body += f"
  • {line[2:]}
  • \n" elif line.startswith('> '): html_body += f"

    {line[2:]}

    \n" else: line = re.sub(r'\*\*(.+?)\*\*', r'\1', line) line = re.sub(r'\[(.+?)\]\((.+?)\)', r'\1', line) line = re.sub(r'`(.+?)`', r'\1', line) html_body += f"

    {line}

    \n" ``` ```python {title} ``` ```python

    {title}

    {author} {" \xb7 " + publish_time if publish_time else ""}
    ``` ### Technical Analysis Title, author, publication time, body text, and extracted link values originate from the remote page. These values are inserted into a generated HTML document without context-aware escaping or a maintained HTML sanitizer. The conversion order creates an additional injection path. Existing tags are removed before HTML entities are decoded. Encoded markup such as `<img src=x onerror=...>` can therefore survive the tag-removal step and be converted back into active markup afterward. `generate_html()` then concatenates that value directly into HTML. Markdown link conversion also inserts the captured destination directly into an `hre ...[truncated 1475 chars]
    Remediation
    View remediation
    Vulnerability Patterns
    • Behavioral ASTexec() Call, eval() Call, Dynamic Import
    • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
    • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
    • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
    • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
    Findings (9)

    Tp4

    High
    Category
    MCP Tool Poisoning
    Confidence
    95% confidence
    Finding

    The skill description promises anti-bot bypass using a real headed browser and says it 'must' be used for WeChat verification scenarios, but the documented behavior is inconsistent and overclaims deterministic bypass capability. This can mislead users or orchestrators into relying on a scraping/anti-detection mechanism that may fail unpredictably or violate platform protections, increasing operational and compliance risk.

    Content

    No source excerpt is available for this finding.

    Undeclared Tool Scope

    Medium
    Category
    MCP Least Privilege
    Confidence
    90% confidence
    Finding

    The skill declares no explicit tool scope or permissions even though it clearly writes files and may inspect environment/display state to decide browser mode. Missing capability boundaries increases the chance the agent invokes the skill with broader access than intended and reduces reviewability for operators.

    Content

    No source excerpt is available for this finding.

    Natural-Language Policy Violations

    Medium
    Category
    Not specified by scanner
    Confidence
    91% confidence
    Finding

    The manifest description is written entirely in Chinese and includes mandatory invocation language such as '必须使用本技能', while the file provides no opt-in or alternative language choice. Under the policy, forcing a specific language or locale without user choice is a natural-language policy violation unless clearly justified as region-specific.

    Content

    No source excerpt is available for this finding.

    Intent-Code Divergence

    Medium
    Category
    Not specified by scanner
    Confidence
    93% confidence
    Finding

    The documentation contains contradictory operational requirements: it says a GUI is required and headed mode is essential, yet also says no-GUI servers will automatically fall back to headless mode. Such contradictions are dangerous because they can cause the skill to run in weaker detection-evasion modes than expected, leading to unreliable behavior and unintended scraping attempts in unsupported environments.

    Content

    No source excerpt is available for this finding.

    Description-Behavior Mismatch

    Medium
    Category
    Not specified by scanner
    Confidence
    90% confidence
    Finding

    The manifest states the skill uses Playwright in headed mode and will pop up a real browser window to bypass anti-bot checks. In code, headless mode is enabled on Linux when no display is present, so the browser window is not always shown and behavior differs from the stated guarantee.

    Content

    No source excerpt is available for this finding.

    Description-Behavior Mismatch

    Medium
    Category
    Not specified by scanner
    Confidence
    98% confidence
    Finding

    The script accepts any http(s) URL and drives a real browser to it, despite the skill claiming it is only for mp.weixin.qq.com public article links. In an agent context, this expands the tool into a general web-fetch capability that can be abused for unintended outbound access, browsing to attacker-controlled pages, and interacting with untrusted web content under the user's network environment.

    Content

    No source excerpt is available for this finding.

    Intent-Code Divergence

    Low
    Category
    Not specified by scanner
    Confidence
    92% confidence
    Finding

    The top-level docstring explicitly presents this script as using Playwright headed mode. Later logic computes a headless flag and may launch the browser without a visible window on Linux without display support, which directly contradicts the documentation.

    Content

    No source excerpt is available for this finding.

    Dynamic attribute access via getattr()

    Low
    Category
    Dangerous Code Execution
    Confidence
    50% confidence
    Finding

    Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

    Content

    Scanner excerpt · scripts/fetch_wechat_article.py (reported line 299)May include surrounding context.

    python
    echo(f"  📺 模式: {'headless' if headless else 'headed'}")
    
        async with async_playwright() as p:
            engine = getattr(p, engine_name)
            launch_kwargs = {
                "headless": headless,
                "args": [
    

    Natural-Language Policy Violations

    Low
    Category
    Not specified by scanner
    Confidence
    94% confidence
    Finding

    This code hard-codes locale="zh-CN" and timezone_id="Asia/Shanghai" for all runs. That is a natural-language policy concern because it imposes a specific locale setting without user opt-in, and the file does not indicate that the tool is restricted to a China-specific compliance or regional use case.

    Content

    No source excerpt is available for this finding.

    Static analysis

    No suspicious patterns detected.