Back to skill

Security audit

qywx-msg-sender

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it claims, but it needs review because it stores and prints webhook secrets and can send user-provided content or files to an unrestricted URL.

Install only if you are comfortable with shell scripts that send selected messages and files to WeCom webhooks. Treat webhook URLs as secrets, avoid using the listing output in shared logs or transcripts, restrict the registry file permissions yourself, and prefer pre-registered trusted destinations over passing arbitrary --url values.

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/wecom_common.sh:195
Finding

Unrestricted Webhook URL Enables SSRF and Sensitive Data Exfiltration

Content
View full analysis
/dev/null || md5sum "$IMAGE_PATH" | awk '{print $1}') BODY=$(jq -n \ --arg base64 "$IMG_BASE64" \ --arg md5 "$IMG_MD5" \ '{ msgtype: "image", image: { base64: $base64, md5: $md5 } }') if wecom_send "$BODY"; then echo "✅ Image sent successfully" else exit 1 fi ``` ### Technical Analysis The destination used by `curl` can originate from the `--url` argument, `WECOM_WEBHOOK_URL`, or the local chat registry. The code only checks whether a URL is present; it does not validate: - The URL scheme - The destination hostname - The destination port - Whether the address resolves to a loopback, private, link-local, o ...[truncated 2380 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/wecom_common.sh:47
Finding

Webhook Authentication Keys Are Exposed in Command Output

Content
View full analysis
"$tmp_file" echo "✅ Registered: $name" echo " Type: $chat_type" echo " URL: $url" echo " ChatID: $chatid" else jq --arg name "$name" --arg url "$url" --arg chat_type "$chat_type" \ '.[$name] = { url: $url, chat_type: $chat_type }' "$WECOM_REGISTRY_FILE" > "$tmp_file" echo "✅ Registered: $name" echo " Type: $chat_type" echo " URL: $url" echo " ChatID: (default group)" fi mv "$tmp_file" "$WECOM_REGISTRY_FILE" ``` The listing function also prints every stored URL without redaction: ```bash list_chats() { ensure_registry local count count=$(jq 'length' "$WECOM_REGISTRY_FILE") if [ "$count" -eq 0 ]; then echo "Registry is empty" return 0 fi echo "Registered chats ($count):" echo "========================================" jq -r 'to_entries | .[] | "\(.key):\n Type: \(.value.chat_type // "group")\n URL: \(.value.url)\n ChatID: \(.value.chatid // "(default group)")\n"' "$WECOM_REGISTRY_FILE" } ``` ### Technical Analysis A WeCom webhook URL includes a secret key in its query string, normally in the form: ```text https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key= ``` Possession of this URL is effectively possession of the credential required to invoke the webhook. The registration and listing functions print the full URL, including its secret query parameter, to standard output. Standard output can be retained in: - AI-agent conversatio ...[truncated 1632 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The code’s primary behavior is consistent with part of the description: it sends Enterprise WeChat robot notifications, specifically Markdown, and supports URL/chatid/name-based targeting through shared helper functions. However, the declared description claims broader multi-format support including text, Markdown V2 with tables, images, and files. This specific supplied code chunk only constructs a markdown payload (msgtype: "markdown") and even explicitly states that tables are not supported here and require a different script. Because the declared purpose materially overstates the capabilities of the supplied code chunk, this is a description/behavior mismatch, though not due to any suspicious undeclared behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

声明描述的核心能力是通过企业微信群机器人 Webhook 发送通知消息;而提供的代码片段实际是一个管理脚本,用于删除已注册的会话,而不是发送文本、Markdown、图片或文件消息。虽然“按名称发送需先注册 webhook URL”暗示系统可能包含会话注册机制,但该片段本身的直接功能是注销会话映射,这属于未在描述中明确体现的管理能力,且与声明的主要用途不同。因此应判定为描述与代码行为不匹配。

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The documentation encourages storing full webhook URLs and chat IDs in a local registry and shows listing them in plaintext, which can expose bearer-style secrets to local users, terminal logs, screenshots, shell history, or CI logs. Because webhook URLs often function as authentication tokens, disclosure can let an attacker send spoofed messages, spam channels, or abuse trusted notification paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This shell script performs a network upload of the user-specified file to the WeCom webhook endpoint using curl. While it prints progress messages, the inline documentation and runtime output do not clearly warn that the file's contents will be transmitted to an external service, which is a safety-relevant disclosure for code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script base64-encodes a local image and sends it via the enterprise WeChat webhook, which is a network transmission of user-provided file data. While there is a progress message indicating that the image is being sent, there is no explicit warning in comments or user-facing output that the file contents will be transmitted to an external service.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This shell script sends the provided content over the network via wecom_send, which is a safety-relevant operation because user-supplied data leaves the local environment. Although usage is documented, the file does not include a clear warning, confirmation, or disclosure that message content will be transmitted to an external Enterprise WeChat webhook.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script's comments, usage examples, error messages, and success output are all written in Chinese, with no option for users to select another language or locale. This creates a natural-language policy issue when language choice is expected unless the locale restriction is explicitly justified.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script stores webhook URLs and ChatIDs in a persistent local registry file under the user's home directory without setting restrictive permissions or warning that credentials are being written to disk. If that file is read by other local users, backup systems, or support tooling, an attacker could recover the webhook secret and send messages into corporate WeCom channels.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script prints full webhook URLs and ChatIDs to stdout during registration and listing. In this context, the webhook URL functions like a secret bearer credential for posting messages, so exposing it in terminal history, logs, CI output, or shared sessions can allow unauthorized message sending to enterprise chats.

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 · scripts/wecom_common.sh (reported line 259)May include surrounding context.

sh
fi

    local resp
    resp=$(curl -s -X POST "$url" \
        -H "Content-Type: application/json" \
        -d "$body")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
94% confidence
Finding

The natural-language comments and usage text are written only in Chinese, which imposes a specific language on readers without offering an alternative or documenting a locale-specific justification. This matches the policy category for language or locale constraints without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The comments, usage instructions, examples, and runtime messages are presented in Chinese only. Under the policy, forcing a specific language without user opt-in is a natural-language policy issue unless the locale restriction is explicitly documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The script's natural-language comments, examples, and user-facing help/error messages are entirely in Chinese, which imposes a specific language on users without opt-in. The file does not indicate that this is a China-only or Chinese-only skill, nor does it offer alternative locale support.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The script’s natural-language comments and runtime error/help output are entirely in Chinese, which enforces a specific language without any user opt-in or alternative locale. This can violate language/locale policy when skills are expected to be language-neutral or to offer user choice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This shell script performs an outbound network operation by calling wecom_send with the constructed message body, which transmits user-provided content to an external chat service. While the file comments describe usage, they do not clearly warn that message content will be sent over the network to a webhook or chat destination.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.