Back to skill

Security audit

Weixin Article Reader

Security checks for vulnerabilities and agentic risk

Overview

The skill’s article-extraction purpose is clear, but its URL validation can be bypassed so a crafted link may make the agent fetch non-Weixin or internal network resources.

Review before installing. The skill is not showing evidence of theft, persistence, or destructive behavior, but it should validate exact HTTPS hostnames and redirects before being trusted in environments with access to private network services. Use only with links you intend to fetch, and treat extracted article text as untrusted content.

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

Error
Location
scripts/extract_wechat_article.py:44
Finding

Server-Side Request Forgery Through Weak Hostname Validation

Content
View full analysis

Vulnerability Details

File Location: scripts/extract_wechat_article.py:44-45, 68
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: High

Vulnerable Code

python
def normalize_url(url: str) -> str:
    parsed = urllib.parse.urlparse(url)
    if "mp.weixin.qq.com" not in parsed.netloc:
        raise ValueError("not a mp.weixin.qq.com url")
    query = urllib.parse.parse_qs(parsed.query, keep_blank_values=True)
    query.setdefault("scene", ["1"])
    new_query = urllib.parse.urlencode(query, doseq=True)
    return urllib.parse.urlunparse(
        (parsed.scheme or "https", parsed.netloc, parsed.path, parsed.params, new_query, parsed.fragment)
    )

The resulting URL is subsequently requested without destination revalidation:

python
with urllib.request.urlopen(req, timeout=20) as resp:
    raw = resp.read()
    charset = resp.headers.get_content_charset() or "utf-8"

Technical Analysis

The validation checks whether the raw network-location string contains mp.weixin.qq.com. This substring test does not verify that the parsed destination hostname is exactly the approved Weixin host.

For example, the following URL passes the check:

text
http://mp.weixin.qq.com@127.0.0.1/

In this URL, mp.weixin.qq.com is user-information, while 127.0.0.1 is the actual destination host. An attacker-controlled hostname containing the trusted string can pass for the same reason.

Additionally, urllib.request.urlopen follows HTTP redirects by default. Even if the initial hostname were validated correctly, the script does not validate redirect destinations, allowing a permitted endpoint to redirect the request to localhost, a private network, or another attacker-selected host.

Attack Path

  1. An attacker supplies a URL whose netloc contains mp.weixin.qq.com, but whose actual hostname points to an unauthorized destination.
  2. normalize_url() accepts the URL because the substring is present.
  3. The recons ...[truncated 1198 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate the parsed hostname rather than searching the raw netloc:
python
parsed = urllib.parse.urlparse(url)
if parsed.scheme != "https":
    raise ValueError("only HTTPS URLs are allowed")
if parsed.hostname != "mp.weixin.qq.com":
    raise ValueError("host is not allowed")
  1. Reject URL credentials and unexpected ports:
python
if parsed.username is not None or parsed.password is not None:
    raise ValueError("URL credentials are not allowed")
if parsed.port not in (None, 443):
    raise ValueError("non-default ports are not allowed")
  1. Resolve the hostname and reject loopback, private, link-local, reserved, multicast, and unspecified addresses. Perform this protection at connection time to reduce DNS rebinding and time-of-check/time-of-use risk.

  2. Disable automatic redirects or implement a redirect handler that validates every redirect target using the same scheme, hostname, port, credential, and resolved-address restrictions.

  3. Maintain an explicit allowlist of approved Weixin hostnames rather than accepting suffixes or substring matches.

  4. Add regression tests covering user-information URLs, deceptive subdomains, attacker-controlled domains containing the trusted text, alternate ports, redirects to private addresses, IPv4 and IPv6 loopback targets, and DNS responses resolving to restricted address ranges.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill instructs the agent to fetch and extract content from external mp.weixin.qq.com URLs, which implies network access, but the manifest does not declare any explicit tool scope or permissions. This creates a least-privilege and governance gap: an agent may use broader-than-necessary network capabilities without clear policy boundaries, making misuse, SSRF-style access through permissive tooling, or unintended data egress harder to prevent and audit.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill can be implicitly invoked based on a broad default prompt to extract content from any mp.weixin.qq.com article link, without clear trigger constraints or user-confirmation boundaries. This increases the chance of overbroad or unintended activation, causing the agent to fetch and process external content when the user did not explicitly request tool use, which can expand attack surface and enable prompt-injection delivery through retrieved article text.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code hard-codes the request header Accept-Language: zh-CN,zh;q=0.9,en;q=0.8, which imposes a locale preference in network behavior. This is a natural-language locale policy concern because the skill does not offer user opt-in or explain why a Chinese-first language setting is required.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.