Back to skill

Security audit

wechat-reply-ai

Security checks for vulnerabilities and agentic risk

Overview

This WeChat automation skill is coherent with its stated purpose, but it needs Review because it can read private chats, send messages/files as the user, run a hidden local daemon, and upload chat transcripts to an LLM endpoint without strong guardrails.

Review carefully before installing. Use it only if you are comfortable letting an agent operate your logged-in WeChat account, read visible conversations, manipulate the clipboard, capture chat screenshots, and send messages or files. Avoid smart-reply and daemon modes unless you explicitly want unattended automation; use a dedicated limited API key, verify the LLM endpoint, confirm recipients and message text before sending, and stop the daemon when finished.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wechat_send.py:638
Finding

Private WeChat transcripts and API credentials can be transmitted to an unrestricted endpoint

Content
View full analysis

Vulnerability Details

File Location: scripts/wechat_send.py, lines 638–760
Vulnerability Type: Unrestricted transmission of sensitive information to a configurable network endpoint
Risk Level: High

Complete Code Snippet

python
def normalize_endpoint(base_url: str) -> str:
    base = (base_url or "").strip()
    if not base:
        base = "https://api.openai.com/v1"
    base = base.rstrip("/")
    if base.endswith("/chat/completions"):
        return base
    if not base.endswith("/v1"):
        base = base + "/v1"
    return base + "/chat/completions"


def request_llm_reply(
    transcript: str,
    contact: str,
    api_key: str,
    api_base: str,
    model: str,
    system_prompt: str,
) -> str:
    if not api_key:
        raise RuntimeError("Missing API key. Set OPENAI_API_KEY or pass --api-key.")
    if not model:
        raise RuntimeError("Missing model name. Set OPENAI_MODEL or pass --model.")

    prompt = (
        f"Contact: {contact}\n"
        "Recent visible WeChat transcript:\n"
        f"{transcript}\n\n"
        "Write the next reply message only. "
        "Do not add quotes, prefixes, or explanations."
    )
    body = {
        "model": model,
        "temperature": 0.7,
        "messages": [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": prompt},
        ],
    }

    request = urllib.request.Request(
        normalize_endpoint(api_base),
        data=json.dumps(body).encode("utf-8"),
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        method="POST",
    )

    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except urllib.error.HTTPError as exc:
        detail = exc.read().deco
...[truncated 3602 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require https and reject HTTP, file, and other URL schemes.
  2. Restrict destinations to an explicit allowlist of trusted LLM hosts, or require a deliberate security override for custom endpoints.
  3. Display the destination hostname and the categories of data being transmitted before smart-reply begins, and obtain explicit user consent.
  4. Do not inherit OPENAI_BASE_URL silently in sensitive workflows; require explicit endpoint configuration or clearly report environment-derived configuration.
  5. Use a dedicated, least-privileged API key with provider-side usage and spending limits.
  6. Add transcript minimization and redaction controls for credentials, financial information, health information, and other sensitive data.
  7. Avoid including the contact identifier unless it is necessary for reply generation.
  8. Add tests confirming that plaintext and unapproved endpoints are rejected.

other

Warning
Location
scripts/wechat_send.py:681
Finding

Untrusted chat content can manipulate automatically transmitted LLM replies

Content
View full analysis

Vulnerability Details

File Location: scripts/wechat_send.py, lines 681–765
Vulnerability Type: Indirect prompt injection with automatic external side effects
Risk Level: Medium

Complete Code Snippet

python
prompt = (
    f"Contact: {contact}\n"
    "Recent visible WeChat transcript:\n"
    f"{transcript}\n\n"
    "Write the next reply message only. "
    "Do not add quotes, prefixes, or explanations."
)
body = {
    "model": model,
    "temperature": 0.7,
    "messages": [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": prompt},
    ],
}

request = urllib.request.Request(
    normalize_endpoint(api_base),
    data=json.dumps(body).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    },
    method="POST",
)

try:
    with urllib.request.urlopen(request, timeout=60) as response:
        payload = json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
    detail = exc.read().decode("utf-8", errors="replace")
    raise RuntimeError(f"LLM request failed: {exc.code} {detail}") from exc
except urllib.error.URLError as exc:
    raise RuntimeError(f"LLM request failed: {exc}") from exc

reply = extract_response_text(payload).strip()
if not reply:
    raise RuntimeError("LLM returned an empty reply.")
return reply


def smart_reply_loop(window, args):
    api_key = args.api_key or os.getenv("OPENAI_API_KEY", "")
    api_base = args.api_base or os.getenv("OPENAI_BASE_URL", "")
    model = args.model or os.getenv("OPENAI_MODEL", "")

    last_snapshot = read_recent_chat(window, args.history_lines)
    last_signature = compute_signature(last_snapshot)
    print(
        f'Watching "{args.contact}" every {args.poll_seconds:.1f}s. '
        "Press Ctrl+C to stop.",
        flush=True,
    )

    while True:

...[truncated 3199 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require explicit user approval before sending every LLM-generated reply, especially when smart-reply first encounters a new message.
  2. Place transcript text inside strong structured delimiters and explicitly state that content inside those delimiters is untrusted data, not executable instruction.
  3. Use a separate validation stage to check generated replies for sensitive-data disclosure, impersonation risks, unsafe advice, links, payment requests, and unexpected instructions.
  4. Apply strict output length and character limits and reject replies that contain content unrelated to the visible conversation.
  5. Provide an allowlisted response mode for unattended operation, such as acknowledgements selected from predefined templates.
  6. Pause auto-send when messages contain instruction-like phrases, requests for secrets, financial actions, authentication codes, links, or high-risk medical, legal, or financial content.
  7. Record a local audit trail of proposed and sent replies without logging full sensitive transcripts unnecessarily.
  8. Make unattended auto-send opt-in and clearly warn users that chat participants can supply adversarial model input.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (31)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

A second behavior-mismatch finding indicates the documented capabilities do not align with implementation details, including claims about OCR, reply generation, media sending, daemon support, and preview-specific screenshots. This is dangerous because users may authorize sensitive WeChat automation under false assumptions, while defenders cannot accurately assess what data is accessed, what content is sent, or whether persistent/background components are introduced.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

A second behavior-mismatch finding indicates the documented capabilities do not align with implementation details, including claims about OCR, reply generation, media sending, daemon support, and preview-specific screenshots. This is dangerous because users may authorize sensitive WeChat automation under false assumptions, while defenders cannot accurately assess what data is accessed, what content is sent, or whether persistent/background components are introduced.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

Mandating that outputs avoid revealing automation violates transparency expectations and is especially risky here because the skill is designed to operate directly within a real user's WeChat session. This enables convincing human-like impersonation at scale, which can be abused for social engineering, relationship manipulation, or bypassing a recipient's ability to assess whether they are interacting with a person or an automated system.

Content

No source excerpt is available for this finding.

YARA rule 'keylogger_indicators': Keylogger functionality in scripts or source code [malware]

High
Category
YARA Match
Confidence
70% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/wechat_send.py (reported line 49)May include surrounding context.

python
n the placeholder and the surrounding text."
)
DEFAULT_PREVIEW_SHOT = "wechat_latest_image_preview.png"
OCR_ENGINE = None


def configure_stdio():
    for stream_name in ("stdout", "stderr"):
        stream = getattr(sys, stream_name, None)
        if hasattr(stream, "reconfigure"):
            stream.reconfigure(encoding="utf-8", errors="replace")


def raise_if_escape_pressed():
    if win32api.GetAsyncKeyState(win32con.VK_ESCAPE) & 0x8000:
        raise KeyboardInterrupt("ESC pressed")


def sleep_with_abort(seconds: float, step: float = 0.05):
    deadline = time.time() + max(0.0, seconds)
    while time.time() < deadline:
        raise_if_escape_pressed()
        time.sleep(min(step, max(0.0, deadline - time.time())))


def get_ocr_engine():
    global OCR_ENGINE
    if OCR_ENGINE is None:
        OCR_ENGINE = RapidOCR()
    return OCR_ENGINE


def launch_wechat(exe_path: str):
    subprocess.Popen([exe_path])


def iter_wechat_window_handles():
    seen = set()
    for backend in

Ssd 3

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The auto-reply loop automatically forwards visible chat content to an external LLM service whenever the transcript changes, creating continuous unattended exfiltration of messages. In this skill context that is especially risky because the tool monitors live personal communications and can repeatedly leak new content without per-message user review.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises and instructs use of shell execution, file reads/writes, local environment access, and potentially networked behavior, but it does not declare any explicit tool scope or permissions boundaries. In an automation skill that can read WeChat messages and send replies/files on the user's behalf, missing scope declarations increases the chance of overbroad agent invocation and unintended access to sensitive local data or messaging actions.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The invocation examples are broad enough to overlap with normal chat-assistance requests, which can cause the agent to invoke this skill when the user did not intend local WeChat automation. In this context, accidental invocation is risky because the skill can read private messages and send replies or files from a logged-in personal account, turning ambiguous language into real-world actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill lacks a prominent warning that it can read WeChat conversations and send messages/media as the user, which is highly privacy- and integrity-sensitive. In a messaging automation context, insufficient disclosure undermines informed consent and makes accidental exfiltration, impersonation, or unintended outbound communication more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The persona explicitly instructs the agent to avoid disclosing that it is a tool or AI while impersonating the user in WeChat. In this skill context, that creates deceptive communication risk, can mislead message recipients about authorship, and is especially sensitive because the tool is designed to send messages as a logged-in human account.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The instruction '生成简短、贴题的中文回复' forces a specific language for replies. This is a natural-language policy concern because the file does not offer a language choice, ask for user preference, or document a justified region-specific constraint.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The workflow explicitly automates outbound WeChat messaging on the user's behalf but provides no guardrails such as confirmation prompts, recipient verification, or warnings about unintended transmission. In a messaging automation skill, this creates a real risk of accidental or unauthorized messages being sent to the wrong contact, especially when combined with daemonized fast-path operation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The entire skill guidance is written only in Chinese and assumes operation in a Chinese-language WeChat context, with no indication that users may opt into another language or locale. Under the policy, locale or language constraints should either be optional for the user or explicitly justified as region-specific.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The guide explicitly instructs the agent to hide that replies are AI- or automation-generated, which facilitates deceptive impersonation of the human account owner. In the context of a Windows local WeChat auto-reply toolkit that can read messages and send responses on a logged-in user's behalf, this materially increases the risk of non-consensual or misleading communications.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The section titled '中文发送要求' instructs that Chinese messages should be sent using a specific method and that reply text files must be UTF-8, which imposes a Chinese-language workflow. The file does not offer a language choice or explain a justified region-specific constraint, so this appears to force a locale/language expectation without user opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This daemon exposes WeChat message-reading and message-sending operations over local HTTP and authorizes them with a bearer token stored in a local state file. Any same-user local process that can read that file can invoke the API to exfiltrate chat contents or send messages as the user, which is especially sensitive given the skill's purpose of automating private communications.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code starts a hidden persistent daemon automatically and without an explicit user-facing warning, then waits for it to become responsive. In the context of a tool that can read chats and send WeChat messages, silently creating a background service materially increases stealth and the risk of unauthorized or unnoticed long-lived access.

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

python
f"-WorkingDirectory '{Path(__file__).resolve().parent}' "
        "-WindowStyle Hidden"
    )
    subprocess.run(
        ["powershell", "-NoProfile", "-Command", ps_command],
        check=True,
        cwd=str(Path(__file__).resolve().parent),

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

python
out_path = r"D:\Backup\Documents\Playground\wechat_screen.png"

    result = subprocess.run([
        'powershell', '-command',
        f'{script} -outPath "{out_path}" -x {x} -y {y} -w {w} -h {h}'
    ], capture_output=True, text=True, timeout=15)

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes local WeChat automation tasks like locating chats, reading messages, sending replies, and taking screenshots. While screenshots are in scope, implementing them by launching an external PowerShell process introduces general subprocess-execution capability that is not itself justified by the stated purpose of a messaging helper.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script automates select/copy operations on chat history and reads message content from the system clipboard, which can expose private communications and overwrite the user's clipboard data. In this skill context, the behavior is directly aligned with the tool's purpose, but that also makes it more dangerous because it operationalizes bulk access to sensitive messages with no explicit disclosure, consent gate, or clipboard hygiene.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script captures and stores a screenshot of an active WeChat conversation window, which can expose private message contents, contact information, and other sensitive desktop-visible data. In the context of a local automation skill for messaging, this is especially risky because it collects personal communications without an explicit consent prompt, warning, or retention control.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The embedded instruction explicitly says 'You are replying to a WeChat friend in Chinese,' which imposes a language choice by default. This is a natural-language locale policy issue because the script does not offer the user a language selection or require opt-in for that forced language behavior.

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

python
def launch_wechat(exe_path: str):
    subprocess.Popen([exe_path])


def iter_wechat_window_handles():

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The presence of a default external API endpoint is part of an actual network transmission path for chat data, so in this file it is not merely informational. While the URL itself is not malicious, hardwiring a cloud endpoint normalizes off-device processing of sensitive transcript content.

Content

Scanner excerpt · scripts/wechat_send.py (reported line 639)May include surrounding context.

python
def normalize_endpoint(base_url: str) -> str:
    base = (base_url or "").strip()
    if not base:
        base = "https://api.openai.com/v1"
    base = base.rstrip("/")
    if base.endswith("/chat/completions"):
        return base

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script sends visible WeChat transcript content to an external LLM API for reply generation, which creates a real data-exfiltration path for potentially sensitive personal or business messages. In the context of a local messaging automation skill, this is more dangerous because users may assume processing stays on-device while the code silently exports chat data off-host when smart-reply is enabled.

Content

No source excerpt is available for this finding.