Back to skill

Security audit

WeChat Article Summarize

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches a WeChat article summarizer, but it needs review because weak URL checks can fetch non-WeChat/internal URLs and article text is sent through an external summarizer with broad environment access.

Install only if you are comfortable with a skill that fetches web pages, saves raw article files locally, and sends article text through your configured summarize tool. Review or fix the URL validation first if this will run on a machine with access to internal services, cloud metadata, or private networks, and avoid using untrusted --env-file values.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/read_wechat_article.py:104
Finding

Arbitrary Outbound Requests Through Inadequate URL Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/read_wechat_article.py, lines 21–28 and 104–107
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: Medium

Vulnerable Code

python
def fetch(url: str, timeout: int = 20):
    req = Request(url, headers={
        'User-Agent': UA,
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache',
    })
    with urlopen(req, timeout=timeout) as resp:
        charset = resp.headers.get_content_charset() or 'utf-8'
        return {
            'status_code': getattr(resp, 'status', None),
            'final_url': resp.geturl(),
            'text': resp.read().decode(charset, errors='replace')
        }
python
url = args.url.strip()
if 'mp.weixin.qq.com' not in url:
    print('URL must point to mp.weixin.qq.com', file=sys.stderr)
    return 2

Technical Analysis

The application intends to restrict network requests to WeChat articles hosted on mp.weixin.qq.com. However, it only checks whether that string occurs anywhere in the complete URL. It does not use the imported urlparse function to verify the actual hostname or scheme.

An attacker can therefore place mp.weixin.qq.com in a path, query string, fragment, username, or attacker-controlled hostname while directing the request to another destination. Examples that pass the substring check include:

text
http://127.0.0.1:8080/private?mp.weixin.qq.com
http://169.254.169.254/latest/meta-data/?mp.weixin.qq.com
https://attacker.example/article/mp.weixin.qq.com
https://mp.weixin.qq.com.attacker.example/

urlopen also follows HTTP redirects by default. Even if the initial URL were validated correctly, a permitted endpoint could redirect the request to localhost, a private network service, a link-local metadata endpoint, or another unauthorized host unless every redirect ...[truncated 1971 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse and validate the URL before constructing the request:
python
from urllib.parse import urlparse

def validate_wechat_url(url: str) -> str:
    parsed = urlparse(url)

    if parsed.scheme != 'https':
        raise ValueError('Only HTTPS URLs are allowed')

    if parsed.hostname != 'mp.weixin.qq.com':
        raise ValueError('URL hostname must be mp.weixin.qq.com')

    if parsed.username is not None or parsed.password is not None:
        raise ValueError('Embedded credentials are not allowed')

    if parsed.port not in (None, 443):
        raise ValueError('Nonstandard ports are not allowed')

    return url
  1. Do not use suffix matching unless subdomains are explicitly required. If they are required, enforce a DNS-label boundary:
python
host == 'mp.weixin.qq.com' or host.endswith('.mp.weixin.qq.com')

Do not use:

python
host.endswith('mp.weixin.qq.com')

because it would accept hosts such as evilmp.weixin.qq.com.

  1. Disable automatic redirects or implement a redirect handler that validates the scheme, hostname, port, and resolved IP address of every redirect target before following it.

  2. Resolve the destination hostname and reject loopback, private, link-local, multicast, reserved, and unspecified addresses using Python's ipaddress module. Repeat this validation for every redirect and connection to mitigate DNS rebinding.

  3. Apply response size limits before reading the full body to reduce denial-of-service exposure.

  4. Stop the workflow when article retrieval has a blocked, partial, or error status instead of unconditionally passing generated files to downstream processing.

  5. Add regression tests covering:

    • 127.0.0.1 and localhost.
    • RFC 1918 private addresses.
    • 169.254.169.254.
    • Hostname suffix confusion.
    • Embedded credentials.
    • Nonstandard ports.
    • Redirects to prohibited destinations.
    • DNS names resolving to private or link-local addresses.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (22)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents an end-to-end WeChat article processing skill: ingest URLs, extract cleaned text and image links, run summarization, and interactively confirm configuration/options before saving the final markdown. This code chunk does not implement those core behaviors. Instead, it is a report-building utility that assumes prior pipeline steps have already produced JSON metadata and summaries in local directories. Its primary function is formatting and saving a markdown report, with optional image counting. Because the implemented behavior is only a downstream aggregation step rather than the described full workflow, the description materially overstates what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a higher-level workflow tool for processing one or more mp.weixin.qq.com article links, optionally extracting images, summarizing content in Chinese, and producing structured markdown output. The supplied code does something much narrower: it parses a local HTML file for a specific embedded WeChat content field, decodes and cleans the HTML into plain text, and saves that text to a specified output file. While this could be a supporting helper for the larger skill, the actual code chunk by itself does not implement several core declared behaviors, especially URL handling, summarization, image extraction, markdown generation, or multi-article reporting. Therefore the description does not accurately represent what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose centers on a workflow for fetching and processing WeChat articles, summarizing them, optionally extracting images, and producing a markdown digest. The supplied code does none of that. Its sole function is to normalize markdown formatting from a local input file to a local output file. This is a materially different primary purpose rather than a partial implementation detail, so it is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The core extraction behavior partly matches the description: it targets mp.weixin.qq.com articles, cleans body text, extracts image URLs, and generates markdown output. However, several key advertised behaviors are absent. The most important mismatch is that the code never calls any summarization system and merely uses the article's existing meta description as a 'Summary' section. It also supports only a single URL argument rather than multi-article processing or daily reports. The described interactive steps—confirming summarize availability, asking whether to include images, and asking where to save—are not implemented. Additionally, the script always saves auxiliary raw HTML and JSON files. These are material differences in functionality, so the description does not accurately represent the supplied code.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose centers on end-to-end WeChat article handling: accepting article links, retrieving and cleaning article content, optionally collecting images, summarizing each article in Chinese, and producing a markdown digest. This code does none of the web retrieval or WeChat-specific extraction. Its sole function is to read already-provided text from a file, invoke an external summarize tool with Chinese settings, validate the result, and save the returned JSON. The only overlap is Chinese summarization and writing to disk, but the primary purpose and capabilities are materially narrower and different from the description.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

md
3. place the combined overview first
4. then append each single article section

## Output rules

### Naming

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
91% confidence
Finding

Passing os.environ.copy() into an external summarization command exposes the entire current environment to that child process, including API keys, credentials, proxy settings, and internal configuration. In this skill context, the summarize binary is an external dependency processing potentially sensitive article text, so broad environment inheritance increases the blast radius if the binary, plugin chain, or remote provider is compromised or overly permissive.

Content

Scanner excerpt · scripts/summarize_cn.py (reported line 45)May include surrounding context.

python
cmd = ['summarize', '-', '--length', args.length, '--json', '--no-cache', '--language', 'zh']
    if args.model:
        cmd += ['--model', args.model]
    proc = subprocess.run(cmd, input=data, text=True, capture_output=True, env=os.environ.copy())
    if proc.returncode != 0:
        sys.stderr.write(proc.stderr or proc.stdout)
        raise SystemExit(proc.returncode)

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation states that summarization is forced to Chinese, which removes user choice and may cause inaccurate summaries or policy/compliance issues for users who expect source-language handling. While not inherently malicious, undocumented locale forcing can mislead users and degrade output quality, especially for multilingual or translation-sensitive content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The README says the workflow calls summarize and asks the user to confirm it is configured, but it does not clearly disclose that full article content may be transmitted to an external summarization provider. This creates a real transparency and data-handling risk because users may provide copyrighted, sensitive, or access-restricted article content without understanding it will leave the local environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill declares broad operational behavior involving shell, filesystem, environment access, and network fetching, but does not constrain those capabilities with explicit tool scope. In an agent setting, missing permission boundaries increases the chance the workflow or bundled scripts could access more resources than necessary if invoked or modified unexpectedly.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The markdown explicitly states that the script enforces Chinese output and fails otherwise. This is a natural-language locale policy constraint presented as mandatory behavior, with no user opt-in or alternative language path described.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The manifest says the skill should summarize each article in Chinese with summarize, but this script only builds markdown from extracted fields, using the page's existing digest when present and otherwise dumping the raw body text. There is no call to any summarization component or generation of a synthesized summary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes support for one or more WeChat article links, including multi-article daily reports, but the CLI parser accepts exactly one positional url argument. No looping, batching, or report aggregation is implemented.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/run_wechat_mindmap_workflow.py (reported line 14)May include surrounding context.

python
def run(cmd, **kwargs):
    proc = subprocess.run(cmd, text=True, capture_output=True, **kwargs)
    if proc.returncode != 0:
        sys.stderr.write(proc.stderr or proc.stdout)
        raise SystemExit(proc.returncode)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The workflow retrieves article content from supplied URLs and then passes extracted body text into a summarization step, which may transmit article or system-provided data to another component or external service. In this file there is no confirmation prompt, print/log disclosure, or comment/docstring warning the user that URL content will be fetched and processed for summarization.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script accepts a user-supplied env file and copies arbitrary key-value pairs into the environment before launching the external summarize tool. This can alter authentication tokens, proxy settings, model/provider selection, or library/runtime behavior in ways that redirect data, weaken security controls, or cause the subprocess to use attacker-chosen services.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The command hard-codes --language zh, and the script then rejects summaries whose Chinese character ratio is below a threshold. This imposes a specific language/locale policy on all users without offering a choice or documenting opt-in behavior.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/summarize_cn.py (reported line 45)May include surrounding context.

python
cmd = ['summarize', '-', '--length', args.length, '--json', '--no-cache', '--language', 'zh']
    if args.model:
        cmd += ['--model', args.model]
    proc = subprocess.run(cmd, input=data, text=True, capture_output=True, env=os.environ.copy())
    if proc.returncode != 0:
        sys.stderr.write(proc.stderr or proc.stdout)
        raise SystemExit(proc.returncode)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The default value for --report-label is the Chinese string 微信文章日报, which imposes a specific language/locale in generated output when the user does not explicitly choose one. This is a natural-language policy concern because the script does not offer an interactive language choice or document a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest says the skill should first confirm summarize is configured and working, ask whether to include images, and ask where to save the final file. This script performs none of those checks or prompts; it always extracts images into metadata when present and proceeds directly based on CLI inputs/defaults.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code fetches remote content from a provided URL and writes the retrieved HTML, generated markdown, and result metadata to disk. While the operations are visible in code, there is no confirmation prompt, docstring, comment, or user-facing notice explaining that remote requests will be made and files will be created locally.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The code accepts an --env-file argument and uses it when invoking the summarization subprocess, which suggests environment-based credentials or sensitive configuration may be loaded. There is no visible warning, log message, or explanatory comment in this file informing the user that external configuration or secrets may be consumed during execution.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.