Back to skill

Security audit

微信公众号文章导出

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it claims: it fetches a WeChat article URL and saves the text as a local Markdown file, with some implementation risks users should understand.

Install in an isolated Python environment if possible, review the output path before running, and treat exported Markdown from untrusted articles as untrusted input if another system will parse its YAML front matter. Publishers should pin dependencies and safely serialize front matter metadata.

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

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unbounded Dependency Resolution Without Integrity Verification

Content
View full analysis

Vulnerability Details

File Location: requirements.txt:1-4
Additional Locations: SKILL.md:43-47, README.md:25-37
Vulnerability Type: Unpinned third-party dependencies and missing package integrity verification
Risk Level: Medium

Vulnerable Code

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

The documentation directs users to install these dependencies:

bash
pip3 install requests beautifulsoup4 lxml markdownify
pip3 install -r requirements.txt

Technical Analysis

Every dependency specifies only a minimum version, with no upper bound, exact version pin, lock file, or cryptographic hash. Consequently, installation may resolve to package releases that did not exist when the skill was reviewed.

Python package installation and subsequent imports can execute package-controlled code. If a permitted dependency or its distribution channel is compromised, following the documented installation process can introduce attacker-controlled code into the environment. The audit found no evidence that the currently named packages are malicious; the weakness is the absence of reproducible and integrity-verified dependency resolution.

Attack Path

  1. An attacker compromises a dependency maintainer account, build pipeline, or package distribution process.
  2. The attacker publishes a malicious release with a version satisfying the configured minimum constraint.
  3. A user follows the documented installation command in a fresh or updated environment.
  4. pip resolves and downloads the compromised release because no exact version or hash prevents it.
  5. Malicious package code executes during installation or when the skill imports the package.
  6. The code operates with the privileges of the user running pip or invoking the exporter.

Impact Assessment

A successful supply-chain compromise could execute arbitrary code with the in ...[truncated 347 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every direct dependency to an exact, reviewed version rather than using open-ended minimum constraints.

  2. Generate a reproducible lock file containing cryptographic hashes for all direct and transitive dependencies.

  3. Require hash verification during installation, for example:

    bash
    python3 -m pip install --require-hashes -r requirements.txt
    
  4. Use a dependency-management tool such as pip-tools, Poetry, or an equivalent solution to review and lock transitive packages.

  5. Run automated dependency vulnerability and provenance checks in CI.

  6. Test dependency upgrades explicitly before updating the lock file.

  7. Recommend installation inside an isolated virtual environment and discourage privileged or system-wide installation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export.py:161
Finding

Remote Article Metadata Is Written to YAML Front Matter Without Safe Serialization

Content
View full analysis

Vulnerability Details

File Location: scripts/export.py:161-169
Vulnerability Type: YAML front-matter injection through unescaped remote metadata
Risk Level: Medium

Vulnerable Code

python
# Write YAML front matter
f.write("---\n")
f.write(f"title: {meta['title']}\n")
f.write(f"author: {meta['author']}\n")
f.write(f"publish_time: {meta['publish_time']}\n")
f.write(f"source_url: {self.url}\n")
f.write(f"exported_at: {datetime.now().isoformat()}\n")
if meta.get('description'):
    f.write(f"description: {meta['description']}\n")
f.write("---\n\n")

Technical Analysis

The title, author, publication time, and description originate in Open Graph metadata extracted from the downloaded HTML page. These remote values are interpolated directly into YAML front matter without YAML serialization, quoting, newline rejection, or scalar escaping.

YAML-sensitive characters and embedded line breaks can therefore terminate an expected scalar or create additional keys, lists, tags, aliases, or document markers. A crafted metadata value could alter the semantic structure of the generated front matter rather than remaining a plain text value.

This code alone does not parse or execute the generated YAML, so direct code execution is not established. Exploitation depends on a downstream Markdown, static-site, indexing, or automation system consuming the exported file and assigning security-sensitive meaning to injected metadata.

Attack Path

  1. An attacker controls or influences a WeChat article whose Open Graph metadata contains YAML syntax or embedded line breaks.
  2. The user asks the skill to export that article.
  3. The exporter downloads the page and extracts the attacker-controlled metadata.
  4. The metadata is inserted verbatim between the YAML document delimiters.
  5. The exported Markdown file contains additional or structurally altered front-matter fields.
  6. A downstream system parses ...[truncated 602 chars]
Remediation
View remediation

Remediation Suggestions

  1. Construct a metadata dictionary and serialize it using a maintained YAML library rather than manually concatenating strings.

  2. Use safe scalar serialization, for example:

    python
    import yaml
    
    front_matter = {
        "title": meta["title"],
        "author": meta["author"],
        "publish_time": meta["publish_time"],
        "source_url": self.url,
        "exported_at": datetime.now().isoformat(),
    }
    
    if meta.get("description"):
        front_matter["description"] = meta["description"]
    
    f.write("---\n")
    yaml.safe_dump(
        front_matter,
        f,
        allow_unicode=True,
        sort_keys=False,
        default_flow_style=False,
    )
    f.write("---\n\n")
    
  3. If adding a YAML dependency is undesirable, normalize line breaks and apply a correct YAML scalar-quoting routine to every externally derived value.

  4. Impose reasonable length limits on metadata fields to prevent oversized or malformed output.

  5. Add tests containing colons, quotes, document delimiters, YAML tags, aliases, and multiline metadata.

  6. Configure downstream systems to use safe YAML loaders and avoid interpreting front-matter values as executable templates or commands.

Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (15)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes a Python script that performs network access and writes files, but the manifest does not declare any explicit tool scope or permissions. This weakens security boundaries and user awareness because the platform cannot constrain or clearly disclose the skill's effective capabilities before execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The description says the skill exports articles to Markdown, but it does not prominently warn that content is written to the local filesystem by default. This can mislead users about persistence behavior and cause unintended storage of remote content in the workspace.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger conditions are broad enough to activate on generic requests about downloading or saving WeChat content, even when the user may not intend to run a filesystem-writing export workflow. Overbroad activation increases the chance of unintended network fetches and local file creation, especially in an agent environment where skill routing may be automatic.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The documented workflow persists downloaded content across the session by creating directories and saving files, without any guardrails described for retention or path restrictions. While persistence is core to the feature, it still raises risk because remote content from a public URL is stored locally and may be reused or trusted later by downstream automation.

Content

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

bash
# 如需要则创建输出目录
mkdir -p "$OUTPUT_DIR"

# 运行导出脚本
python3 ~/.npm-global/lib/node_modules/openclaw/skills/WeChat-article-reader/scripts/export.py "$URL" "$OUTPUT_DIR"

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The documented workflow persists downloaded content across the session by creating directories and saving files, without any guardrails described for retention or path restrictions. While persistence is core to the feature, it still raises risk because remote content from a public URL is stored locally and may be reused or trusted later by downstream automation.

Content

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

bash
# 如需要则创建输出目录
mkdir -p "$OUTPUT_DIR"

# 运行导出脚本
python3 ~/.npm-global/lib/node_modules/openclaw/skills/WeChat-article-reader/scripts/export.py "$URL" "$OUTPUT_DIR"

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This is a markdown file, so SQP-2 applies to omissions in user-facing warnings. The document states that the skill will automatically fetch article content and save a Markdown file, but it does not clearly warn users that using the skill performs outbound HTTP requests and writes files to disk, which can affect privacy and local data.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The example utterances include conversational phrases that overlap with normal assistant behavior, making accidental invocation more likely. In this skill's context, accidental activation can still trigger network retrieval and persistent writes, so even low-friction examples increase operational risk.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

The dependency specification uses a lower-bound version only, which allows future installs to resolve to different releases over time. This weakens build reproducibility and makes it hard to verify whether a deployed version includes known vulnerable releases or breaking changes.

Content

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

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

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

requests has multiple published advisories, but because the manifest does not pin an exact version, it is impossible to determine from this file whether a safe or affected release will be installed. In a network-fetching skill, this uncertainty matters because the library directly handles attacker-controlled URLs and HTTP responses.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

beautifulsoup4 is not pinned to an exact version, so installations may vary across environments and dates. That creates supply-chain uncertainty and complicates auditing, testing, and incident response if a bad release is introduced.

Content

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

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

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

Using lxml with only a minimum version allows dependency drift and makes security posture unverifiable at install time. In a skill that parses remote HTML content, uncertainty around parser/library versions is more concerning because parser bugs can be security-relevant.

Content

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

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

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

lxml has known security advisories, and the unpinned requirement prevents verification that deployed environments avoid affected versions. This is somewhat more dangerous in this skill because lxml processes untrusted remote HTML, so parser or sanitizer flaws could potentially be triggered by malicious article content.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
96% confidence
Finding

markdownify is unpinned, so the actual installed version may change unexpectedly and could include vulnerable or unstable behavior. Since this skill converts untrusted remote article HTML into Markdown, deterministic dependency versions are important for safety and reproducibility.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

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

Unverifiable Dependency: markdownify has 2 known advisory(ies) (CVE-2025-46656 (markdownify allows large headline prefixes such as <h9999999>, which causes memo); CVE-2025-46656 (markdownify allows large headline prefixes such as <h9999999>, which causes memo)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
88% confidence
Finding

markdownify has known advisories and the dependency is not pinned, so the installed version may still be vulnerable. Because this skill converts attacker-controlled HTML into Markdown, malformed input could exploit parser/conversion edge cases such as resource exhaustion in affected versions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The HTTP request headers force Accept-Language to zh-CN,zh;q=0.9,en;q=0.8, which encodes a specific locale preference in the skill behavior. The file does not provide a user opt-in, configuration option, or documented justification for this locale restriction, so it fits the natural-language locale policy concern.

Content

No source excerpt is available for this finding.