Back to skill

Security audit

WeChat AI Monitor

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent RSS monitor that fetches configured feeds and writes local Markdown reports, with some ordinary hardening gaps users should understand.

Install only if you are comfortable with the skill contacting each enabled RSS URL from your machine and writing reports under ~/.config/wechat-monitor/reports. Configure trusted HTTPS feeds, keep accounts.json under your control, and treat report content from untrusted feeds as untrusted Markdown.

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
skill.py:96
Finding
Unrestricted RSS URLs Enable Server-Side Request Forgery## Vulnerability Details **File Location**: `skill.py:96-100`, with configuration data reaching the sink at `skill.py:164-170` **Vulnerability Type**: Server-Side Request Forgery **Risk Level**: High ### Vulnerable Code ```python def parse_rss(rss_url, source_name): try: # Download RSS headers = {'User-Agent': 'Mozilla/5.0'} response = requests.get(rss_url, headers=headers, timeout=15) ``` The request target originates directly from the configuration: ```python name = account['name'] rss_url = account.get('rss_url', '') report_content += f"## {name}\n\n" if rss_url == "待填写": report_content += "*该账号的 RSS URL 未配置*\n\n" continue articles = parse_rss(rss_url, name) ``` ### Technical Analysis The application sends a server-side HTTP request to a configuration-controlled URL without validating its scheme, hostname, resolved address, port, or redirect destination. The `requests` library also follows redirects by default. Consequently, an attacker who can influence `accounts.json` can direct the process to request loopback addresses, private network services, link-local resources, cloud metadata services, or an external redirector that forwards the request to such destinations. The request is made with the network access privileges of the user and host running the skill. Although the response must resemble RSS XML for structured extraction, connection behavior and error output can still facilitate internal service probing. Internal content formatted as qualifying RSS can be written into a report and printed to the console. ### Attack Path 1. The attacker obtains the ability to create or modify `~/.config/wechat-monitor/accounts.json`. 2. The attacker adds an enabled account whose `rss_url` references an internal service, metadata endpoint, loopback address, or attacker-controlled redirector. 3. A user or automated process executes `python skill.py`. 4. `requests. ...[truncated 919 chars]
Remediation
## Remediation Suggestions - Allow only HTTPS URLs. - Maintain an explicit allowlist of approved RSS domains where operationally possible. - Resolve each hostname before connecting and reject loopback, private, link-local, multicast, reserved, and unspecified addresses for both IPv4 and IPv6. - Disable automatic redirects or validate the scheme, hostname, port, and resolved address of every redirect destination. - Protect against DNS rebinding by connecting only to the validated resolved address while preserving correct TLS hostname verification. - Reject URLs containing embedded credentials or unexpected ports. - Apply outbound firewall or proxy restrictions so the process cannot access metadata and internal management networks. - Treat the configuration file as security-sensitive and restrict its ownership and permissions.

T09 · Insecure Skill Coding Practices

Warning
Location
skill.py:96
Finding
Unbounded RSS Response Parsing Can Cause Resource Exhaustion## Vulnerability Details **File Location**: `skill.py:96-104` **Vulnerability Type**: Uncontrolled Resource Consumption **Risk Level**: Medium ### Vulnerable Code ```python def parse_rss(rss_url, source_name): try: # Download RSS headers = {'User-Agent': 'Mozilla/5.0'} response = requests.get(rss_url, headers=headers, timeout=15) response.raise_for_status() # Parse XML root = ET.fromstring(response.text) ``` ### Technical Analysis The application buffers the complete remote response in memory and then parses the entire document as XML. It does not enforce a maximum response size, XML depth, element count, field size, or number of articles. The configured timeout does not impose a strict maximum response size. In `requests`, the timeout primarily controls periods of network inactivity rather than the total number of bytes that can be downloaded. A malicious or compromised RSS endpoint can therefore return a very large response while continuing to transmit data. After downloading the response, `response.text` creates a decoded text representation, and `ET.fromstring()` constructs an in-memory XML tree. These stages can increase peak memory consumption. Processing a feed containing an excessive number of items can also consume significant CPU and produce an oversized report. ### Attack Path 1. The attacker controls an enabled RSS endpoint or compromises an existing configured endpoint. 2. The endpoint returns an extremely large XML response or a document containing an excessive number of nested elements and RSS items. 3. The skill buffers the entire HTTP response in memory. 4. The response is decoded and parsed into an in-memory XML tree. 5. Memory and CPU consumption increase until the process slows down, is terminated, or affects other workloads on the host. ### Impact Assessment Exploitation affects the availability of the process and potentially th ...[truncated 418 chars]
Remediation
## Remediation Suggestions - Download responses in streaming mode and stop once a strict byte limit is reached. - Validate `Content-Length` when present, while still enforcing the limit during streaming. - Accept only expected RSS or XML content types. - Use a hardened XML parser and explicitly prohibit unsupported XML constructs. - Parse incrementally rather than constructing the entire XML tree in memory. - Set limits for XML depth, element count, number of RSS items, title length, link length, and description length. - Apply a total request deadline in addition to connection and read timeouts. - Limit the maximum generated report size. - Run the monitor with operating-system memory, CPU, file-size, and execution-time limits.

T09 · Insecure Skill Coding Practices

Note
Location
skill.py:177
Finding
Untrusted RSS Fields Are Written as Unsanitized Markdown## Vulnerability Details **File Location**: `skill.py:177-180` **Vulnerability Type**: Markdown Content Injection **Risk Level**: Low ### Vulnerable Code ```python report_content += f"### {article['title']}\n" report_content += f"**发布时间**: {article['pubdate']}\n" report_content += f"**链接**: {article['link']}\n" report_content += f"**摘要**: {article['summary']}\n\n" ``` ### Technical Analysis Article titles, publication dates, links, and summaries originate from remote RSS content and are concatenated directly into a Markdown document. The earlier `strip_html()` operation removes strings resembling HTML tags, but it does not escape Markdown control characters or validate URL schemes. A malicious feed can therefore inject headings, links, images, block quotes, or other renderer-specific Markdown constructs. The injected content may visually alter report structure, impersonate trusted report sections, or cause a Markdown renderer to request an attacker-controlled remote image. A crafted link can also direct users to a deceptive or unsafe destination. The precise effect depends on the Markdown renderer. The source code does not itself execute the injected content, so this issue is primarily relevant when generated reports are opened in a renderer that supports active links, remote images, or unsafe extensions. ### Attack Path 1. The attacker controls or compromises a configured RSS feed. 2. The attacker publishes an item containing Markdown syntax in its title, link, publication date, or summary. 3. The item includes a recent publication date and an AI or technology keyword so it passes the filters. 4. The skill inserts the attacker-controlled fields directly into the report. 5. A user opens the report in a Markdown renderer. 6. The injected content alters the report presentation, presents a deceptive link, or triggers a remote-resource request if supported by the renderer. ### Impact Assessment Exploitation doe ...[truncated 529 chars]
Remediation
## Remediation Suggestions - Escape Markdown metacharacters in every untrusted text field before adding it to the report. - Validate article links and permit only expected schemes such as HTTPS. - Reject dangerous or unexpected URL schemes. - Format URLs through a dedicated Markdown-link encoder rather than direct concatenation. - Render remote fields as plain text where clickable links are not required. - Disable raw HTML and unsafe Markdown extensions in downstream renderers. - Configure renderers not to load remote images automatically. - Consider storing structured report data separately and generating display output through a context-aware Markdown renderer.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
Comments, status messages, and generated report content are written in Chinese throughout the file, and the script does not provide an option to select another language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
The natural-language policy check applies to all file types. The primary description is in Chinese and the file does not state that the skill is region-specific or offer users an English/locale alternative, which can amount to forcing a language without opt-in.

Missing User Warnings

Low
Confidence
82% confidence
Finding
This is a markdown file, so missing-warning review applies. The document describes automatic Markdown report generation and instructs the user to edit a configuration file under ~/.config, but it does not explicitly warn that the skill will create or update local files; users may not realize it changes data on disk.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"author": "Molty",
  "license": "MIT",
  "dependencies": {
    "requests": "^2.25.0"
  }
}
Confidence
94% confidence
Finding
The dependency version is specified with a caret range (^2.25.0), which allows automatic installation of newer minor/patch releases rather than a fully pinned version. This increases supply-chain risk and can lead to non-reproducible builds or accidental adoption of a compromised or breaking upstream release, though the package.json alone does not indicate active malicious behavior.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.25.0
Confidence
95% confidence
Finding
The dependency is specified as `requests>=2.25.0`, which allows any future version and does not guarantee a reviewed, reproducible package set. This creates supply-chain and patch-management risk because deployments may resolve to different versions over time, including versions with incompatible behavior or newly introduced vulnerabilities.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
91% confidence
Finding
Because `requests` is not pinned, it is impossible to verify from this manifest whether the installed version is affected by known advisories. In practice this can result in environments resolving to a vulnerable release, including versions affected by credential leakage or other security issues, making the risk context-dependent but real.

Intent-Code Divergence

Low
Confidence
86% confidence
Finding
The top-of-file comments describe a '微信公众号监控脚本' that parses RSS and extracts articles from the past 24 hours. In implementation, the script never interacts with WeChat-specific APIs or identifiers; it simply reads arbitrary `rss_url` values from a local JSON config and fetches them over HTTP. This is an intent/documentation mismatch rather than just missing detail, because the comment frames the target platform more specifically than the code enforces.

Missing User Warnings

Low
Confidence
76% confidence
Finding
This code performs outbound HTTP requests to each configured RSS endpoint using requests.get, which can disclose the user's monitored sources and system IP to third parties. While the script prints that it is fetching articles, it does not clearly warn that it will contact external servers and transmit request metadata.

Static analysis

No suspicious patterns detected.