Back to skill

Security audit

微信文件助手

Security checks for vulnerabilities and agentic risk

Overview

This is a local WeChat file search and indexing skill whose sensitive local indexing behavior is disclosed and aligned with its purpose.

Install only if you are comfortable with a local searchable database of WeChat file paths, hashes, extracted text, file timestamps, and optional metadata being stored under LOCALAPPDATA. Prefer narrow explicit roots for sensitive accounts, avoid indexing untrusted Office files when possible, and remove the local index when you no longer need it.

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

Warning
Location
scripts/wechat_file_index.py:133
Finding

Unbounded Decompression and XML Parsing of Untrusted Office Documents

Content
View full analysis

Vulnerability Details

File Location: scripts/wechat_file_index.py:133-154
Vulnerability Type: Uncontrolled resource consumption through unbounded archive decompression and XML parsing
Risk Level: Medium

Vulnerable Code

python
def extract_docx(path: Path) -> tuple[str, str]:
    with zipfile.ZipFile(path) as archive:
        xml = archive.read("word/document.xml")
    root = ET.fromstring(xml)
    parts = [node.text for node in root.iter() if node.tag.endswith("}t") and node.text]
    return "\n".join(parts)[:MAX_CONTENT_CHARS], "extracted"


def extract_xlsx(path: Path) -> tuple[str, str]:
    parts: list[str] = []
    with zipfile.ZipFile(path) as archive:
        names = archive.namelist()
        if "xl/sharedStrings.xml" in names:
            root = ET.fromstring(archive.read("xl/sharedStrings.xml"))
            parts.extend(node.text for node in root.iter() if node.tag.endswith("}t") and node.text)
        for name in names:
            if re.fullmatch(r"xl/worksheets/sheet\d+\.xml", name):
                root = ET.fromstring(archive.read(name))
                parts.extend(node.text for node in root.iter() if node.text and node.tag.endswith(("}v", "}t")))
                if sum(len(item) for item in parts) >= MAX_CONTENT_CHARS:
                    break
    return "\n".join(parts)[:MAX_CONTENT_CHARS], "extracted"

Technical Analysis

DOCX and XLSX files are ZIP archives containing XML members. The extraction functions use ZipFile.read() to decompress each selected member completely into memory and then pass the complete byte string to ElementTree.fromstring().

The implementation does not check:

  • The member's uncompressed size.
  • The ratio between compressed and uncompressed sizes.
  • The total amount of data decompressed from an archive.
  • The number or aggregate size of worksheet members.
  • The time or memory consumed by XML parsing.

`MAX_CONTEN ...[truncated 2310 chars]

Remediation
View remediation

Remediation Suggestions

  1. Inspect every relevant ZipInfo entry before extraction and reject members whose declared uncompressed size exceeds a conservative limit.

  2. Enforce limits for both individual members and the whole archive, including:

    • Maximum uncompressed bytes per member.
    • Maximum aggregate uncompressed bytes.
    • Maximum number of worksheet members.
    • Maximum compression ratio.
  3. Replace unbounded archive.read(name) calls with bounded streaming reads. Stop reading and report a dedicated status such as archive_member_too_large once the byte limit is exceeded.

  4. Parse XML incrementally with ElementTree.iterparse() or an equivalently constrained parser, clearing processed elements as parsing proceeds. Stop once the text or byte budget is reached.

  5. Perform all size checks before XML parsing. Do not rely on truncating the final extracted string because that occurs after the expensive operations.

  6. Run document extraction in an isolated worker process with memory and execution-time limits. Terminate the worker cleanly if either limit is exceeded so the main indexing operation can continue.

  7. Catch resource-limit and malformed-archive failures per file, store an explicit content_status, and continue indexing other files.

  8. Add regression tests using highly compressed Office fixtures, oversized XML members, excessive worksheet counts, malformed archives, and files near each configured limit.

Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding

The skill invokes local PowerShell scripts to search and index files and explicitly describes reading local filesystem content, but it does not declare any tool scope such as allowed-tools or permissions. This creates a governance gap: an agent or reviewer cannot easily constrain or audit the skill’s access to filesystem and environment capabilities, increasing the risk of over-broad file access or unintended data exposure from local WeChat files.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The default prompt authorizes broad local file search and follow-on file processing without clear user-trigger constraints, scope limits, or confirmation boundaries. In a skill that operates on local Windows WeChat files, this can enable over-collection or unintended handling of sensitive personal documents when invoked from vague user requests.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The top-level docstring says "Read-only WeChat file catalog," which implies non-mutating behavior. In reality, the script creates database directories/tables, inserts and updates indexed file records during builds, and modifies sender/chat metadata via the import-metadata command.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script extracts file contents and metadata from WeChat-related directories and persists them into a local SQLite database under LOCALAPPDATA. Because these files may contain sensitive personal or business information, silently creating a searchable secondary datastore increases confidentiality risk if the machine, user profile, or database file is later accessed by another process or user.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

During build, the tool reads user documents, extracts text from supported formats, hashes files, and stores the resulting content in a persistent index without any explicit warning at execution time. In the WeChat-file context, this is more sensitive than generic desktop indexing because it may capture private chats, attachments, invoices, legal documents, or corporate data that users may not expect to be re-materialized into a separate searchable store.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The display name, short description, and default prompt are all written only in Chinese, which implies a fixed language presentation without any visible user opt-in or documented locale limitation. This can violate language or locale policy when the skill does not explicitly offer a language choice or justify being region-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

When the OpenInExplorer switch is set, the script launches explorer.exe to select a matching file, which is a subprocess/system action. The file contains no inline warning, confirmation prompt, or user-facing disclosure around this behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes broader end-user capabilities including opening file locations and continuing with downstream processing such as summarization or comparison. This file implements indexing, searching, duplicate detection, metadata import, and status reporting only, so the described behavior is broader than what the code here actually does.

Content

No source excerpt is available for this finding.