Back to skill

Security audit

微信公众号文章爬虫

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to do what it says, but it can fetch arbitrary URLs and download unbounded content, which is broader than a WeChat article downloader should need.

Install only if you are comfortable running a network downloader. Use it with trusted WeChat article URLs, run it in a dedicated output directory, and prefer a sandbox or outbound network restrictions until the skill validates domains, blocks private-network destinations, and limits download sizes.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scraper.py:8
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: scripts/main.py:31-42, scripts/scraper.py:8-18, and scripts/images.py:28-37, 47-58
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: High

Vulnerable Code

scripts/main.py:31-42:

python
article_url = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else DEFAULT_OUTPUT_DIR

# 创建输出目录
os.makedirs(output_dir, exist_ok=True)

print(f"📥 抓取文章:{article_url}")

# 1. 抓取文章
html = fetch_article(article_url)

scripts/scraper.py:8-18:

python
def fetch_article(url: str) -> Optional[str]:
    """抓取文章 HTML 内容"""
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    }

    try:
        response = requests.get(url, headers=headers, timeout=15)

scripts/images.py:47-58:

python
def extract_images(html_content: str, base_url: str) -> List[Tuple[str, str]]:
    """从 HTML 中提取所有图片 URL"""
    from bs4 import BeautifulSoup

    soup = BeautifulSoup(html_content, 'lxml')
    images = []

    # 查找所有 img 标签
    for img in soup.find_all('img'):
        src = img.get('src') or img.get('data-src')
        if src:
            # 处理相对 URL
            full_url = urljoin(base_url, src)
            images.append((full_url, img))

scripts/images.py:28-37:

python
def download_image(url: str, save_path: str, timeout: int = 10) -> bool:
    """下载单张图片"""
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Referer': 'https://mp.weixin.qq.com/'
    }

    try:
        response = requests.get(url, headers=headers, timeout=timeout
...[truncated 2542 chars]
Remediation
View remediation

Remediation Suggestions

  1. Permit only the schemes required by the Skill, preferably HTTPS, and reject URLs containing credentials or unsupported ports.
  2. Enforce an explicit hostname allowlist for article pages, such as the intended WeChat article domain, and a narrowly defined list of approved image CDN domains.
  3. Resolve each hostname before connecting and reject every resolved IPv4 and IPv6 address in loopback, private, link-local, multicast, unspecified, reserved, and other non-public ranges.
  4. Disable automatic redirects or validate the scheme, hostname, port, and resolved addresses of every redirect target before following it.
  5. Apply the same validation to the initial article URL, all image URLs, and all redirect destinations.
  6. Protect against DNS rebinding by ensuring that validation and connection use consistent resolution results or by enforcing destination controls at an outbound proxy or firewall.
  7. Run the downloader in a sandbox with outbound network access restricted to the approved domains.
  8. Add tests covering direct private IP addresses, IPv6 loopback, alternative numeric IP representations, user-information URL syntax, DNS names resolving to private addresses, and redirects to prohibited destinations.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/images.py:37
Finding

Unbounded HTML and Image Downloads Allow Resource Exhaustion

Content
View full analysis

Vulnerability Details

File Location: scripts/scraper.py:18-21 and scripts/images.py:37-42, 53-58
Vulnerability Type: Uncontrolled Resource Consumption
Risk Level: Medium

Vulnerable Code

scripts/scraper.py:18-21:

python
response = requests.get(url, headers=headers, timeout=15)
response.raise_for_status()
response.encoding = response.apparent_encoding  # 自动检测编码
return response.text

scripts/images.py:37-42:

python
response = requests.get(url, headers=headers, timeout=timeout, stream=True)
response.raise_for_status()

with open(save_path, 'wb') as f:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)

scripts/images.py:53-58:

python
# 查找所有 img 标签
for img in soup.find_all('img'):
    src = img.get('src') or img.get('data-src')
    if src:
        # 处理相对 URL
        full_url = urljoin(base_url, src)
        images.append((full_url, img))

Technical Analysis

The article response is loaded into memory through response.text without checking Content-Length or enforcing a maximum number of received bytes. Encoding detection through apparent_encoding also operates on the downloaded content. A hostile or compromised server can therefore return an oversized document and cause substantial memory and CPU consumption.

Image responses are streamed to disk, but the loop has no per-file or aggregate byte limit. The parser also accepts an unlimited number of image elements. Timeouts limit waiting behavior but do not bound the amount of data transferred by a server that continuously supplies data. No response media-type validation ensures that the downloaded body is actually an image, and failed transfers can leave partial files behind.

Attack Path

  1. An attacker supplies an article URL served by a system under their control.
  2. The server returns an extremely large HTML response, causing the client to retain and ...[truncated 1065 chars]
Remediation
View remediation

Remediation Suggestions

  1. Stream article responses rather than accessing response.text directly, count received bytes, and abort when a conservative maximum HTML size is exceeded.
  2. Set a maximum size for each image and a maximum aggregate download size for the entire article.
  3. Limit the number of images processed per article and deduplicate URLs before initiating downloads.
  4. Reject responses whose declared Content-Length exceeds the applicable limit, while still enforcing the limit during streaming because that header may be absent or false.
  5. Validate article and image Content-Type values against a narrow allowlist. Do not rely solely on filename extensions.
  6. Use separate connect and read timeouts, limit redirects, and enforce an overall operation deadline.
  7. Write downloads to temporary files, remove partial files on every error or limit violation, and atomically rename files only after successful validation.
  8. Consider checking image signatures and dimensions before accepting files, including limits that prevent decompression-bomb processing by downstream tools.
  9. Run the Skill with filesystem quotas and restricted CPU, memory, and execution-time limits as defense in depth.

T08 · Insecure Dependencies

Warning
Location
scripts/requirements.txt:1
Finding

Open-Ended Dependency Constraints Prevent Reproducible and Verifiable Installation

Content
View full analysis

Vulnerability Details

File Location: scripts/requirements.txt:1-3 and SKILL.md:10-13
Vulnerability Type: Unpinned Third-Party Dependencies
Risk Level: Medium

Vulnerable Code

scripts/requirements.txt:1-3:

text
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

SKILL.md:10-13:

bash
cd scripts && pip install -r requirements.txt && python main.py

Technical Analysis

Every dependency uses an open-ended minimum-version constraint. Installation can therefore select any later version available from the configured package index, including releases that did not exist when the Skill was reviewed. The dependency graph is neither locked nor protected by artifact hashes.

The documented execution procedure installs dependencies immediately before running the application. As a result, identical Skill source can produce different installed code over time. If an eligible direct or transitive dependency release, package index, or distribution artifact is compromised, package installation may execute unreviewed build or installation behavior and the runtime will import unreviewed code.

No evidence was found that the named packages are typosquatted or currently malicious. The confirmed issue is the lack of reproducible version and integrity controls, not a claim that the listed projects are malicious.

Attack Path

  1. A user follows the documented command and invokes pip install -r requirements.txt.
  2. Pip resolves the newest eligible direct and transitive package versions from its configured index because no upper or exact versions are specified.
  3. A compromised, malicious, or unexpectedly incompatible eligible release is selected.
  4. Pip installs that release; package build or installation logic may run with the user's privileges.
  5. The application subsequently imports and executes the installed dependency code.

Exploitation requires compromise or malici ...[truncated 721 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace open-ended constraints with exact, reviewed versions for direct and transitive dependencies.
  2. Generate a lock file using a reproducible dependency-management workflow and commit it to the project.
  3. Record cryptographic hashes for every accepted distribution and install with hash verification, such as pip's --require-hashes mode.
  4. Use a trusted, explicitly configured package index or an internally controlled artifact repository rather than relying on ambient index configuration.
  5. Prefer prebuilt, reviewed wheels where appropriate and prevent unexpected source builds in production installation workflows.
  6. Add automated vulnerability and license scanning for the complete resolved dependency graph.
  7. Update dependencies through a controlled process that reviews changelogs, security advisories, hashes, and compatibility tests before changing the lock file.
  8. Separate dependency installation from routine Skill execution so each invocation does not dynamically resolve and install potentially different code.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (12)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill invokes dependency installation, network access, and local file writes, but it does not declare any explicit tool scope or permissions. This weakens user awareness and policy enforcement, making it easier for a user or execution framework to run a network-and-write capable skill without clear consent boundaries.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language content in the description, instructions, features, usage, and notes is all presented in Chinese. Under the stated policy, forcing a specific language without user opt-in or documented justification is a locale/language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The module docstring is entirely in Chinese and all user-facing CLI messages are also presented only in Chinese, which imposes a single language/locale on users. The file does not offer any language selection, fallback, or justification that this is a region-specific tool with a documented locale requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The Accept-Language header is fixed to prefer zh-CN and zh, which imposes a specific locale on all requests. This is a natural-language policy concern because the file does not offer opt-in, configuration, or explanation that the skill is intentionally region-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation describes downloading article content and images but does not clearly warn that running the skill will create Markdown files and an images directory on local disk. This can lead to unintended local writes, clutter, or overwriting expectations in environments where users assume analysis-only behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code fetches remote content with requests.get and writes it to disk via open(save_path, 'wb'), which are safety-relevant operations under the rule. Aside from an error print on failure, there is no confirmation, informational log before execution, or warning comment/docstring that clearly tells a user the function will contact external URLs and save files locally.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency is specified with a lower-bound constraint only, which makes builds non-reproducible and can cause unexpected installation of vulnerable or breaking upstream releases over time. In a web-scraping skill that fetches and parses untrusted remote content, dependency drift increases supply-chain and security risk because networking and parsing libraries are security-relevant.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

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
92% confidence
Finding

The manifest does not pin requests, so there is no way to verify whether deployments will receive a version affected by known advisories or a patched one. Since this skill performs outbound HTTP requests to retrieve article content, an unverified networking library version increases uncertainty around credential handling, TLS, redirects, and other security-sensitive behavior.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Using an unpinned beautifulsoup4 version allows different environments to resolve to different releases, reducing reproducibility and making it unclear which security fixes are actually present. Because this skill parses external HTML from WeChat articles, parser-library version control matters for reliability and security hardening.

Content

Scanner excerpt · scripts/requirements.txt (reported line 2)May include surrounding context.

text
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

An unpinned lxml dependency is a genuine supply-chain hygiene issue because lxml is a native parsing library with a history of security advisories. In this skill's context, it processes remote HTML/XML-like content, so allowing arbitrary future versions to be installed increases exposure to parser-related flaws or unexpected behavior.

Content

Scanner excerpt · scripts/requirements.txt (reported line 3)May include surrounding context.

text
requests>=2.31.0
beautifulsoup4>=4.12.0
lxml>=4.9.0

Unverifiable Dependency: lxml has 14 known advisory(ies) (CVE-2021-43818 (lxml's HTML Cleaner allows crafted and SVG embedded scripts to pass through); CVE-2014-3146 (lxml Cross-site Scripting Via Control Characters); CVE-2021-28957 (lxml vulnerable to Cross-Site Scripting ) +11 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

Because lxml is not pinned, the environment may install a release with known advisories, and the manifest provides no assurance that a safe version is used. This is more relevant here because the skill ingests and parses untrusted external article markup, making parser security directly tied to the application's attack surface.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The function performs a network request to an arbitrary URL, which necessarily sends the requested URL and headers such as User-Agent and Accept-Language to a remote server. While there is error logging on failure, there is no comment, docstring warning, or user-facing disclosure that the skill will contact external servers and transmit request metadata.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.