Back to skill

Security audit

公众号作者文章抓取

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real local WeChat article fetcher, but it handles account sessions and includes unsafe cleanup, dependency, and URL-handling paths that need review before installation.

Install only if you are comfortable giving this skill local shell, network, browser-profile, and WeChat session access. Use a dedicated low-privilege WeChat Official Accounts account, avoid shared or synced folders for the skill directory, do not share QR/login artifacts casually, pin and review dependencies before first run, and avoid clear-login when WECHAT_FETCHER_PROFILE_DIR or WECHAT_FETCHER_LOGIN_ARTIFACTS_DIR are set to custom paths.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:753
Finding

Authentication Cookies May Be Disclosed to Unvalidated Article Destinations

Content
View full analysis
httpx.AsyncClient: return httpx.AsyncClient( headers=base_headers(), cookies=cookies, follow_redirects=True, timeout=httpx.Timeout(30.0, connect=30.0), ) ``` ```python async def download_articles( *, cookies: dict[str, str], articles: list[dict[str, Any]], output_dir: Path, account: dict[str, Any], concurrency: int, ) -> list[dict[str, Any]]: semaphore = asyncio.Semaphore(max(concurrency, 1)) async with build_async_client(cookies) as client: tasks = [ download_single_article( client=client, semaphore=semaphore, index=index, article=article, output_dir=output_dir, account=account, ) for index, article in enumerate(articles, start=1) ] return await asyncio.gather(*tasks) async def download_single_article( *, client: httpx.AsyncClient, semaphore: asyncio.Semaphore, index: int, article: dict[str, Any], output_dir: Path, account: dict[str, Any], ) -> dict[str, Any]: async with semaphore: try: response = await client.get(article["link"]) response.raise_for_status() parsed = parse_article_content(response.text, article) ``` ### Technical Analysis The asynchronous HTTP client is initialized with cookies extracted from the authenticated WeChat browser session. These cookies are supplied as a plain name-to-value dictionary instead of cookie objects with explicit domain and path restrictions. The same authenticated client is then used to request every URL found in `a ...[truncated 1874 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:241
Finding

Environment-Controlled Cache Paths Permit Recursive Deletion of Arbitrary Directories

Content
View full analysis
dict[str, Any]: removed_paths: list[str] = [] if PROFILE_DIR.exists(): shutil.rmtree(PROFILE_DIR) removed_paths.append(str(PROFILE_DIR)) if LOGIN_ARTIFACTS_DIR.exists(): shutil.rmtree(LOGIN_ARTIFACTS_DIR) removed_paths.append(str(LOGIN_ARTIFACTS_DIR)) return { "status": "cleared", "removed_paths": removed_paths, "profile_dir": str(PROFILE_DIR), "login_artifacts_dir": str(LOGIN_ARTIFACTS_DIR), } ``` ### Technical Analysis The paths deleted by `command_clear_login()` can be overridden through `WECHAT_FETCHER_PROFILE_DIR` and `WECHAT_FETCHER_LOGIN_ARTIFACTS_DIR`. The values are used without canonicalization or safety validation. The function does not verify that the selected paths: - Are descendants of the Skill directory or a dedicated cache root. - Have the expected cache directory names. - Are different from the project root, user home, or filesystem root. - Do not resolve through unsafe path components. - Actually contain Skill-generated authentication artifacts. The documented workflow encourages users and Agents to invoke `clear-login` when handing the project to another person. A poisoned or accidentally misconfigured execution environment can therefore convert a legitimate cleanup command into destructive deletion of unrelated data. ### Attack Path 1. An attacker-controlled wrapper, automation configuration, shell profile, or poisoned environment sets one of the pat ...[truncated 822 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
scripts/run_fetcher.sh:1
Finding

Automatic Installation of Mutable, Unpinned Dependencies Creates a Supply-Chain Execution Risk

Content
View full analysis
=4.12.3 httpx>=0.27.0 markdownify>=0.13.1 pillow>=11.1.0 playwright>=1.52.0 ``` ### Technical Analysis The launcher automatically creates a virtual environment and invokes pip whenever `.venv/bin/python` is absent. Every dependency uses only a lower-bound version constraint. As a result, the effective code installed and executed can change after the Skill has been audited. No lock file, exact version pin, package hash, or trusted artifact constraint is used. Pip may execute package build or installation logic, and imported dependencies execute with the same privileges as the Skill. The listed package names are conventional, and the audit found no custom package index, obvious typosquatting, or known malicious package deliberately included in the repository. The vulnerability is the mutable and automatically executed dependency resolution process. ### Attack Path 1. The Skill is run on a system where `scripts/.venv/bin/python` does not exist. 2. `run_fetcher.sh` automatically invokes pip without a separate approval step. 3. Pip resolves the newest available versions satisfying the lower bounds, including transitive dependencies. 4. An upstream package or transitive dependency is compromised, taken over, or replaced with a malicious release. 5. Malicious code executes during installation, import, or runtime with the privileges of the Agent user. ### Impact Assessment A compromised dependency could access all resources available to the Skill process, including: - ...[truncated 347 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:382
Finding

Sensitive Browser Profile and Login QR Artifacts Are Created Without Explicit Restrictive Permissions

Content
View full analysis
tuple[str, dict[str, str]]: PROFILE_DIR.mkdir(parents=True, exist_ok=True) LOGIN_ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True) ``` ```python def write_login_qr_artifacts( *, png_bytes: bytes, qr_signature: str, display_mode: str, quiet: bool, ) -> str: png_path = LOGIN_ARTIFACTS_DIR / "login_qr.png" txt_path = LOGIN_ARTIFACTS_DIR / "login_qr.txt" png_path.write_bytes(png_bytes) ascii_qr = render_qr_ascii(png_bytes) txt_path.write_text(ascii_qr + "\n", encoding="utf-8") ``` ```python def write_login_status(status: str, display_mode: str, **payload: Any) -> None: status_path = LOGIN_ARTIFACTS_DIR / "login_status.json" data = { "status": status, "display_mode": display_mode, "updated_at": datetime.now().isoformat(timespec="seconds"), **payload, } status_path.write_text( json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8", ) ``` ### Technical Analysis The persistent Playwright profile may contain authenticated browser state, cookies, local storage, and other session-related information. The login artifact directory contains an active QR image, a text representation of that QR code, and status metadata. The directories and files are created with process-default permissions. The implementation does not explicitly enforce: - Mode `0700` for authentication directories. - Mode `0600` for QR and status files. - Ownership checks. - Permission repair for existing files. - Prompt deletion of expired QR artifacts. On systems with permissive umasks, shared workspaces, or multiple local users, these artifacts may ...[truncated 1011 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (23)

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The trigger language is intentionally broad and directs the agent to prioritize this skill even for casual, colloquial mentions, which can cause the skill to activate without clear, informed user consent. Because this skill performs high-impact actions—shell execution, dependency installation, config edits, local credential reuse, and bulk network scraping—overbroad triggering materially raises the risk of unintended execution and data handling.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `./scripts/requirements.txt`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- `./scripts/requirements.txt`

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The README describes output directories and login cache locations elsewhere, but the flagged section does not clearly warn users up front that the tool will persist scraped article content locally and retain authenticated session artifacts. In an agent-driven workflow, that omission can cause operators to run the skill without realizing it creates local copies of third-party content and sensitive login state, increasing the chance of accidental data exposure, repo commits, or unsafe sharing of the project folder.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to read and modify local files, create virtual environments, install dependencies, invoke shell scripts, and perform network-backed scraping, but it declares no explicit tool scope or permission boundaries. In an agent environment, this creates excessive implicit authority: the skill can trigger sensitive filesystem, shell, and network actions without a machine-readable restriction layer, increasing the chance of overreach or misuse if invoked on ambiguous user requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documentation explicitly suggests sending the generated login QR code image through IM for scanning, but does not warn that possession of that QR can allow another party to authenticate the WeChat account tied to the session. In this skill’s context, the QR is a live authentication artifact, so casual sharing materially increases account takeover and privacy risk, especially when used by agents or automation that may forward artifacts broadly.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

clear-login recursively deletes the Playwright profile directory and login artifacts directory, which are persistent local state. In an agent/tooling context, destructive deletion unrelated to content fetching can cause loss of authentication state and potentially remove more data than intended if the environment variables point to unexpected locations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code deletes stored login/profile directories immediately with shutil.rmtree and no warning or confirmation. Because these paths are influenced by environment variables, misuse or malicious invocation could wipe persistent browser/login data unexpectedly and disrupt other local workflows.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/main.py (reported line 296)May include surrounding context.

python
def default_output_parent() -> Path:
    # In the bundled skill package, keep output under the skill root so agents
    # can use the tool without asking the user for a separate output path.
    skill_root = APP_ROOT.parent
    if (skill_root / "SKILL.md").exists():
        return skill_root

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes a local WeChat article fetcher that batches article retrieval and outputs files, but this code also executes local OS commands via osascript to show dialogs and spawns external viewer processes to display QR images. These subprocess/GUI capabilities are not an obvious requirement of article scraping itself and introduce broader host interaction than the skill's stated purpose suggests.

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/main.py (reported line 358)May include surrounding context.

python
def run_osascript(script: str) -> str | None:
    try:
        result = subprocess.run(
            ["osascript", "-e", script],
            capture_output=True,
            text=True,

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/main.py (reported line 673)May include surrounding context.

python
close_qr_viewer()
    try:
        if sys.platform == "darwin":
            ACTIVE_QR_VIEWER = subprocess.Popen(
                ["qlmanage", "-p", str(path)],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,

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/main.py (reported line 680)May include surrounding context.

python
)
            return
        if shutil.which("xdg-open"):
            ACTIVE_QR_VIEWER = subprocess.Popen(
                ["xdg-open", str(path)],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The default headers hard-code Accept-Language to zh-CN, and related request parameters elsewhere also fix lang=zh_CN. This imposes a specific language/locale behavior without offering user choice or documenting opt-in, matching the policy category for language or locale constraints.

Content

No source excerpt is available for this finding.

Tainted flow: 'article_url' from input (line 376, user input) → httpx.get (network output)

Medium
Category
Data Flow
Confidence
98% confidence
Finding

The tool accepts a user-supplied article_url and fetches it directly with httpx.get and redirects enabled, without validating scheme, host, or destination. In an agent setting this creates an SSRF-style capability: an attacker can make the skill send arbitrary outbound requests, potentially to internal services, localhost, or tracking endpoints rather than genuine WeChat article URLs.

Content

Scanner excerpt · scripts/main.py (reported line 773)May include surrounding context.

python
def fetch_seed_article_info(article_url: str) -> dict[str, Any]:
    response = httpx.get(
        article_url,
        headers={
            "User-Agent": USER_AGENT,

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens reproducibility and can silently introduce vulnerable or incompatible releases through normal dependency updates or supply-chain compromise.

Content

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

text
beautifulsoup4>=4.12.3
httpx>=0.27.0
markdownify>=0.13.1
pillow>=11.1.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

Using httpx>=0.27.0 leaves the actually installed version unconstrained above the minimum, so environments may pull different releases with different security properties. In a scraping skill that performs network access, this increases supply-chain and patch-verification risk because you cannot prove which version is deployed.

Content

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

text
beautifulsoup4>=4.12.3
httpx>=0.27.0
markdownify>=0.13.1
pillow>=11.1.0
playwright>=1.52.0

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), 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 httpx, so it is impossible to verify from this file whether deployment will use a vulnerable or patched release. In a network-heavy scraping skill, unverifiable dependency state reduces assurance and can expose the runtime to known library flaws if resolution selects an affected version.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The markdownify dependency is unpinned, so builds are not reproducible and may unexpectedly consume a release with a security regression or breaking behavior. Because this skill converts scraped HTML into Markdown, parser-related bugs could affect availability or content processing safety.

Content

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

text
beautifulsoup4>=4.12.3
httpx>=0.27.0
markdownify>=0.13.1
pillow>=11.1.0
playwright>=1.52.0

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

Because markdownify is not pinned, the file cannot demonstrate that the installed version avoids the listed advisories. Given this skill ingests untrusted remote HTML and transforms it, parser/resource-exhaustion issues in an affected release could be reachable and harm availability.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

Pillow is unpinned despite being a historically security-sensitive image-processing library. Since the skill may fetch and process remote content, leaving Pillow version selection open increases the chance of pulling a vulnerable build that could enable denial of service or worse when handling crafted images.

Content

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

text
beautifulsoup4>=4.12.3
httpx>=0.27.0
markdownify>=0.13.1
pillow>=11.1.0
playwright>=1.52.0

Unverifiable Dependency: pillow has 16 known advisory(ies) (CVE-2016-2533 (Pillow buffer overflow in ImagingPcdDecode); CVE-2023-50447 (Arbitrary Code Execution in Pillow); CVE-2021-27922 (Pillow Uncontrolled Resource Consumption) +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
96% confidence
Finding

Pillow has many historical advisories, and this manifest does not pin a version, so you cannot tell whether installs are safe. In the context of scraping and processing remote content, an affected Pillow version could be exposed to crafted images, making denial of service and potentially more severe memory-safety issues more plausible than for a typical library.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The Playwright dependency is specified with only a minimum version, making installations non-deterministic. For a browser automation component that interacts with external web content, unpinned versions increase both supply-chain risk and operational instability across environments.

Content

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

text
httpx>=0.27.0
markdownify>=0.13.1
pillow>=11.1.0
playwright>=1.52.0