Back to skill

Security audit

向企业微信发送消息

Security checks for vulnerabilities and agentic risk

Overview

This Enterprise WeChat messaging skill is purpose-aligned overall, but it needs review because it can read arbitrary local paths or fetch arbitrary URLs as images and send the data to a user-specified webhook.

Review before installing. Use this only with approved Enterprise WeChat webhook URLs, avoid sending secrets or private operational data, do not pass untrusted local paths or URLs as images, and consider adding allowlists, file type and size checks, SSRF protections, and explicit confirmation for @all messages and custom destinations.

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

Error
Location
scripts/send_message.py:270
Finding

Unrestricted image retrieval and webhook destinations enable SSRF and arbitrary file disclosure

Content
View full analysis

Vulnerability Details

File Location: scripts/send_message.py:40-78, scripts/send_message.py:270-283
Vulnerability Type: Server-Side Request Forgery (SSRF), arbitrary local file read, and uncontrolled outbound data transmission
Risk Level: High

Vulnerable Code

python
# Default webhook address
if webhook_url is None:
    webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key"

# Construct message data
message_data = construct_message_data(content, msg_type)

if message_data is None:
    return {
        "success": False,
        "error": f"消息格式错误: 不支持的消息类型或内容格式"
    }

try:
    # Send HTTP request
    data = json.dumps(message_data).encode('utf-8')
    req = urllib.request.Request(
        webhook_url,
        data=data,
        headers={'Content-Type': 'application/json'},
        method='POST'
    )

    ssl_context = ssl.create_default_context()

    with urllib.request.urlopen(
        req,
        timeout=10,
        context=ssl_context
    ) as response:
        result = json.loads(response.read().decode('utf-8'))
python
try:
    # Determine whether this is a local file or URL
    if image_path.startswith(('http://', 'https://')):
        # Download image from URL
        with urllib.request.urlopen(image_path, timeout=10) as response:
            image_content = response.read()
    else:
        # Read local image file
        if not os.path.exists(image_path):
            return None

        with open(image_path, 'rb') as f:
            image_content = f.read()

    # Calculate MD5
    md5_hash = hashlib.md5(image_content).hexdigest()

    # Encode as Base64
    base64_content = base64.b64encode(image_content).decode('utf-8')

    return {
        "base64": base64_content,
        "md5": md5_hash
    }

Technical Analysis

The process_image() function treats any string beginning with http:// or https:// as a remotely retrievable image. It does not validate the hostname, resolved IP a ...[truncated 3356 chars]

Remediation
View remediation

Remediation Suggestions

  1. Restrict webhook destinations

    • Allowlist the expected WeCom hostname and endpoint path.
    • Require HTTPS for all webhook requests.
    • Reject embedded credentials, unexpected ports, fragments, and malformed URLs.
    • Store approved webhook URLs in protected configuration rather than accepting arbitrary command-line values.
    • Require explicit user confirmation before transmitting local or internally retrieved content to a custom destination.
  2. Prevent SSRF

    • Parse URLs with urllib.parse.urlsplit() rather than relying on string prefixes.
    • Resolve destination hostnames and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges.
    • Apply the same validation to every redirect destination, or disable redirects.
    • Protect against DNS rebinding by connecting only to the validated resolved address while preserving correct TLS hostname verification.
    • Allowlist trusted image-host domains when practical.
  3. Constrain local file access

    • Restrict images to explicitly approved directories.
    • Resolve paths with Path.resolve() and verify that the canonical target remains beneath an approved root.
    • Reject symbolic links where they are not required.
    • Verify that the target is a regular file.
    • Validate the file using its signature rather than its extension alone.
    • Reject unsupported formats before encoding or transmitting the content.
  4. Enforce resource limits

    • Check local file size before reading.
    • Read local and remote content incrementally with a strict maximum, such as the documented 10 MB image limit.
    • Reject responses with excessive Content-Length values.
    • Stop streaming once the maximum accepted byte count is exceeded.
    • Apply connection and total-transfer timeouts.
  5. Reduce accidental disclosure

    • Separate local-file, remote-image, and webhook capabilities into explicit options.
    • Display the resolved source and ...[truncated 228 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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 (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented purpose says this is a message-sending skill, but the behavior extends to reading local files, fetching remote URLs, and defaulting text messages to broad @all mentions. That mismatch can enable unintended local file access, server-side request behavior, and disruptive mass notifications beyond what a user may reasonably expect from the description.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill documents and implies outbound network activity to Enterprise WeChat webhooks, but it does not declare any explicit tool scope or permission boundary. Missing scope declarations make it harder for users or the hosting agent to understand and constrain data egress, increasing the chance that sensitive content is sent externally without informed approval.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill explains how to send messages to WeChat webhooks but does not clearly and prominently warn that user-supplied message content will be transmitted to an external third-party service. In an agent setting, this can cause accidental disclosure of sensitive internal data, secrets, or personal information through routine use of the skill.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_documentation.md (reported line 223)May include surrounding context.

md
}
        }
    
    response = requests.post(
        webhook_url,
        json=message,
        headers={'Content-Type': 'application/json'}

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/api_documentation.md (reported line 245)May include surrounding context.

cURL调用示例

bash
# 发送文本消息
curl -X POST \
  https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=your-key \
  -H 'Content-Type: application/json' \
  -d '{

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The examples repeatedly encourage sending operational status, deployment details, meeting information, images, and custom webhook URLs to an external Enterprise WeChat endpoint without any explicit warning about data sensitivity, recipient scope, or webhook secrecy. In practice, users may copy these examples and transmit internal infrastructure details or leak the bot webhook, enabling unintended disclosure or unauthorized message sending.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The module docstring and all user-facing CLI help/output strings are written only in Chinese, which imposes a specific language on users without any opt-in or alternative locale path. Under the policy for natural-language violations, a skill should not force a language or locale unless it is explicitly optional or clearly justified as region-specific.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The image handler accepts arbitrary http(s) URLs and fetches them server-side before re-encoding and forwarding them. This expands the skill from simple webhook delivery into unrestricted outbound network access, which can be abused for SSRF-style probing, internal metadata access, or fetching attacker-controlled large/hostile content if untrusted input reaches image_path.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

All user-facing instructions and examples in the skill are presented only in Chinese, and the description states requirements in a strict manner without indicating that language is optional or that the skill is intentionally limited to Chinese-speaking users. Under the language/locale policy, forcing a specific language without user opt-in can be a natural-language policy issue unless clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file presents all instructions, examples, and operational guidance exclusively in Chinese. Under the policy rule for natural-language violations, forcing a specific language without user opt-in can be a locale policy issue when no alternative language or justification is provided.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.