Back to skill

Security audit

企微智能表格

Security checks for vulnerabilities and agentic risk

Overview

This skill matches its WeCom automation purpose, but it needs review because it can send sensitive business data, create scheduled command-based reminders, and store full records locally.

Review this skill before installing. Use it only in a controlled WeCom workspace, keep webhook keys out of source files, require confirmation before sending notifications or creating reminders, and change the tracker to store only minimal reminder fields rather than full business records.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:170
Finding
Command Injection Risk in Dynamically Generated Scheduled Reminder Commands## Vulnerability Details **File Location**: `SKILL.md:170-184` **Vulnerability Type**: Shell command injection through unescaped dynamic reminder fields **Risk Level**: High ### Vulnerable Code ```text Use the WorkBuddy automation_update tool to create a one-time scheduled task. Parameters: - mode: "suggested create" - name: "Task reminder-{task name}" - scheduleType: "once" - scheduledAt: ISO 8601 format - status: "ACTIVE" - prompt: contains a curl command that directly calls the group robot Prompt template: Send a reminder message to the task group. Execute the following command: curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={TASK_BOT_KEY}" -H "Content-Type: application/json" -d '{"msgtype":"markdown","markdown":{"content":"**Task reminder**\n\n> Task: <font color=\"warning\">{task name}</font>\n> Responsible person: {responsible person}\n> Deadline: {deadline}\n> Status: {status}\n\nPlease process it promptly!"}}' Report the result briefly after sending. ``` The snippet above is an English rendering of the command template at the specified source lines; its command structure and dynamic interpolation points are unchanged. ### Technical Analysis The Skill directs an agent to interpolate task names, responsible-party values, deadlines, and status values directly into a JSON document enclosed in a shell command argument. It does not require JSON serialization, shell escaping, input validation, or execution without a command shell. If any interpolated field contains a single quote, shell metacharacters, command substitution syntax, or crafted JSON delimiters, the value can terminate the `-d` argument and introduce additional shell commands. JSON escaping alone would not be sufficient because the resulting value must also remain safe for the shell quoting context. This risk is particularly significant because the command is saved in a scheduled automation prompt. Exploitation can ...[truncated 1337 chars]
Remediation
## Remediation Suggestions 1. Do not store dynamically constructed shell commands in automation prompts. 2. Use a structured HTTP client or dedicated WeCom notification tool that accepts the URL and JSON body as separate typed parameters. 3. Serialize message bodies with a trusted JSON serializer rather than string concatenation. 4. If curl must be invoked, execute it through an argument array with shell processing disabled, such as `subprocess.run([...], shell=False)`. 5. Never place untrusted values inside a shell command string, even if JSON escaping has been applied. 6. Validate field length and expected character ranges before creating a reminder. 7. Store only a record identifier in the scheduled task where possible, then load and serialize the record safely when the reminder runs. 8. Add tests using quotes, newlines, semicolons, command substitutions, and malformed JSON to verify that user input cannot alter command structure.

T09 · Insecure Skill Coding Practices

Warning
Location
references/wecom_smartsheet.py:24
Finding
Webhook Credentials Are Intended to Be Stored Directly in Source Code and Command URLs## Vulnerability Details **File Location**: `references/wecom_smartsheet.py:24-38` **Vulnerability Type**: Insecure secret storage and exposure through URL query parameters **Risk Level**: Medium ### Vulnerable Code ```python # Configuration area — replace with your own Webhook Key before first use # Smart Sheet webhook URLs TABLE_WEBHOOKS = { "expense": "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={EXPENSE_WEBHOOK_KEY}", "task": "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={TASK_WEBHOOK_KEY}", "video": "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={VIDEO_WEBHOOK_KEY}", } # Group robot webhook URLs BOT_WEBHOOKS = { "expense": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={EXPENSE_BOT_KEY}", "task": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={TASK_BOT_KEY}", "video": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={VIDEO_BOT_KEY}", } ``` Equivalent hardcoded URL templates also appear in `references/wecom_daily_check.py:19-24`. The setup instructions at `SKILL.md:591-597` direct users to place the keys into the scripts. The comments in the snippet are rendered in English, while the executable configuration statements match the audited source. ### Technical Analysis The project instructs operators to replace placeholders directly in Python source files. Once configured, valid WeCom webhook credentials become plaintext source-code constants. The credentials are also embedded in URL query parameters. Full URLs can be exposed through source-control history, backups, copied project archives, shell history, automation prompts, process inspection, exception diagnostics, HTTP client instrumentation, or logs that record request URLs. WeCom webhook keys operate as bearer-style credentials: possession of a valid URL can be sufficient to invoke the associated webhook. The code does not use environment variab ...[truncated 1354 chars]
Remediation
## Remediation Suggestions 1. Remove instructions that tell operators to insert credentials directly into tracked source files. 2. Load keys at runtime from a managed secret store or protected environment variables. 3. Construct webhook URLs only in memory immediately before use. 4. Ensure logs, exceptions, and diagnostics redact the `key` query parameter. 5. Do not embed credential-bearing URLs in scheduled prompts or shell commands. 6. Add configured source files and local secret files to `.gitignore`, while keeping only a credential-free example configuration in the repository. 7. Apply restrictive filesystem permissions to any local secret file. 8. Rotate any webhook key that has entered source control, logs, shell history, backups, or automation metadata. 9. Where supported, restrict webhook use by source network, integration identity, or narrowly scoped permissions.

T09 · Insecure Skill Coding Practices

Warning
Location
references/wecom_smartsheet.py:435
Finding
Complete Business Records Are Persisted in an Unprotected Plaintext Tracker## Vulnerability Details **File Location**: `references/wecom_smartsheet.py:435-493` **Vulnerability Type**: Excessive plaintext retention of sensitive financial and personnel data **Risk Level**: Medium ### Vulnerable Code ```python def save_tracker(records: list): """Save local deadline tracking records.""" with open(TRACK_FILE, "w", encoding="utf-8") as f: json.dump(records, f, ensure_ascii=False, indent=2) def track_record(table: str, data: dict, record_id: str = ""): """Record local deadline information after a successful submission.""" tracker = load_tracker() deadline_fields = { "expense": "Payment deadline", "task": "Planned end time", "video": "Planned video-production completion date", } deadline_key = deadline_fields.get(table, "") deadline_val = data.get(deadline_key, "") name_fields = { "expense": "Expense description", "task": "Detailed task description", "video": "AI-generated video title", } name_key = name_fields.get(table, "") name_val = data.get(name_key, "") responsible_fields = { "expense": "Initial financial reviewer", "task": "Fully responsible person", "video": "Fully responsible video producer", } resp_key = responsible_fields.get(table, "") resp_val = data.get(resp_key, "") entry = { "table": table, "record_id": record_id, "name": name_val, "deadline": deadline_val, "responsible": resp_val, "data": data, "tracked_at": datetime.now().isoformat(), "notified": False, } tracker.append(entry) save_tracker(tracker) ``` Field labels and comments in this presentation are translated into English. The security-relevant behavior is unchanged: the complete `data` dictionary is assigned to the tracker entry and serialized to a ...[truncated 1999 chars]
Remediation
## Remediation Suggestions 1. Remove the complete `"data": data` field from tracker entries. 2. Persist only the minimum fields required for deadline evaluation and notification. 3. Explicitly exclude bank account numbers, account-holder names, bank names, payment details, approval comments, document URLs, and unrelated personnel fields. 4. Create the tracker with restrictive permissions, such as owner read/write access only. 5. Use authenticated encryption if sensitive local persistence remains operationally necessary. 6. Define retention periods and delete completed, canceled, expired, or already-notified records when no longer needed. 7. Add the tracker path to repository ignore rules and exclude it from routine project sharing. 8. Validate existing tracker files and securely remove previously retained sensitive fields. 9. Consider storing opaque record identifiers and retrieving authorized display data only when a reminder must be sent.
Vulnerability Patterns
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The declared purpose emphasizes general WeCom smart-table operations, but the skill also persists local state, sends outbound group notifications, and creates scheduled tasks. This mismatch can mislead users and host systems about the actual behavior, causing unintended disclosure, persistence, and autonomous follow-up actions beyond what the description suggests.

Vague Triggers

High
Confidence
96% confidence
Finding
The trigger list includes very broad, common business phrases such as task creation, reimbursement, reminders, workflow, and inspection terms. This can cause accidental invocation on ordinary conversations, leading to unintended record creation, external notifications, local persistence, or scheduled reminders without the user's informed intent.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs capabilities that require network access, local file reads/writes, and scheduled automation, but it declares no explicit tool scope or permission boundaries. This increases the chance of the runtime granting broader-than-expected authority, enabling silent data transmission, persistence, and automation without clear least-privilege controls.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill directs the agent to write local tracker data, send external webhook messages, and create scheduled automation, but it does not prominently require user-facing disclosure or consent for persistence and third-party notification. In context, the skill handles business tasks, expense data, personnel identifiers, deadlines, and group messaging, so silent operation can expose sensitive operational data and create ongoing side effects.

External Transmission

Medium
Category
Data Exfiltration
Content
| 步骤 | 操作 | 执行方式 | 说明 |
|---|---|---|---|
| **① 写入表格** | 构造 payload,POST 到表格 Webhook | `curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={key}" -H "Content-Type: application/json" -d '{payload}'` | payload 中 `add_records[0].values` 的 key 是字段 ID,value 按字段类型传值 |
| **② 群通知** | 发送 Markdown 消息到对应群机器人 | `curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={bot_key}" -H "Content-Type: application/json" -d '{markdown_payload}'` | 必须发到该表格对应的群,不能发错 |
| **③ 本地追踪** | 同步写入 `wecom_deadline_tracker.json` | 调用 Python 脚本 `track_record()` 或手动追加 JSON | 记录到期信息,供每日巡检脚本读取 |
| **④ 设置提醒** | 创建一次性定时提醒,到期前发到对应群 | WorkBuddy `automation_update` 工具,`scheduleType="once"`,prompt 中用 curl 调群机器人 | 提醒消息发到对应群 |
Confidence
93% confidence
Finding
This instruction sends structured business data to an external WeCom webhook endpoint. External transmission is expected for the feature, but without strong guardrails it can leak task, expense, or personnel data to the wrong tenant, wrong sheet, or an attacker-controlled webhook if keys are misconfigured or substituted.

External Transmission

Medium
Category
Data Exfiltration
Content
| 步骤 | 操作 | 执行方式 | 说明 |
|---|---|---|---|
| **① 写入表格** | 构造 payload,POST 到表格 Webhook | `curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={key}" -H "Content-Type: application/json" -d '{payload}'` | payload 中 `add_records[0].values` 的 key 是字段 ID,value 按字段类型传值 |
| **② 群通知** | 发送 Markdown 消息到对应群机器人 | `curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key={bot_key}" -H "Content-Type: application/json" -d '{markdown_payload}'` | 必须发到该表格对应的群,不能发错 |
| **③ 本地追踪** | 同步写入 `wecom_deadline_tracker.json` | 调用 Python 脚本 `track_record()` 或手动追加 JSON | 记录到期信息,供每日巡检脚本读取 |
| **④ 设置提醒** | 创建一次性定时提醒,到期前发到对应群 | WorkBuddy `automation_update` 工具,`scheduleType="once"`,prompt 中用 curl 调群机器人 | 提醒消息发到对应群 |
Confidence
94% confidence
Finding
This step sends group robot notifications externally, potentially disclosing internal workflow, personnel, deadline, and expense details to chat recipients. Because the skill enforces notifications as mandatory for each operation, accidental or misrouted messages become more dangerous and can amplify data exposure beyond the original requester.

External Transmission

Medium
Category
Data Exfiltration
Content
}
```

**curl 完整示例(工作任务系统):**
```bash
curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={TASK_WEBHOOK_KEY}" \
  -H "Content-Type: application/json" \
Confidence
92% confidence
Finding
The example operational flow includes direct POSTs to external webhook endpoints with record contents, reinforcing that the skill performs live data exfiltration from the host environment to third-party services. In a business context, even legitimate webhook use is sensitive because entries may include employee IDs, deadlines, workflow status, and reimbursement details.

External Transmission

Medium
Category
Data Exfiltration
Content
- `scheduleType`: `"once"`
- `scheduledAt`: ISO 8601 格式,如 `"2026-04-28T09:00"`
- `status`: `"ACTIVE"`
- `prompt`: 包含 curl 命令,直接调群机器人发送提醒

**prompt 模板:**
```
Confidence
95% confidence
Finding
The skill embeds executable curl commands inside automation prompts so that future scheduled jobs can send external messages autonomously. This creates delayed, persistent side effects that may outlive the original user session, increasing the risk of unauthorized messaging, stale reminders, or abuse if prompts, keys, or task contents are tampered with.

External Transmission

Medium
Category
Data Exfiltration
Content
**② 写入表格:**
```bash
curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/wedoc/smartsheet/webhook?key={TASK_WEBHOOK_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "add_records": [{
Confidence
92% confidence
Finding
This example again demonstrates direct external transmission of business records to WeCom webhooks. Repeated operational guidance normalizes sending potentially sensitive enterprise data without explicit mention of secret protection, endpoint validation, or user approval, making accidental disclosure more likely in practice.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code file contains user-facing natural-language text exclusively in Chinese, including the script description and later notification content, but provides no opt-in or configurable language/locale selection. Under the policy rule, forcing a specific language without user choice is a natural-language policy violation unless the locale restriction is explicitly justified.

External Transmission

Medium
Category
Data Exfiltration
Content
}

    try:
        resp = requests.post(webhook_url, json=payload, timeout=10)
        result = resp.json()
        if result.get("errcode") == 0:
            print(f"  ✅ {TABLE_NAMES.get(table, table)} 通知已发送")
Confidence
88% confidence
Finding
This script transmits generated reminder content to external WeCom bot webhooks, which can include task names, deadlines, and responsible persons. In the context of an enterprise workflow skill, sending operational data to chat groups is expected, but it still creates a real data-exposure risk if webhook URLs are misconfigured, leaked, or mapped to the wrong groups.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"📤 推送到 [{table}] 表格...")
    print(f"   数据: {json.dumps(data, ensure_ascii=False)}")
    
    resp = requests.post(url, json=payload, timeout=10)
    result = resp.json()
    
    if result.get("errcode") == 0:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"📤 推送到 [{table}] 表格...")
    print(f"   数据: {json.dumps(data, ensure_ascii=False)}")
    
    resp = requests.post(url, json=payload, timeout=10)
    result = resp.json()
    
    if result.get("errcode") == 0:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
print(f"📤 推送到 [{table}] 表格...")
    print(f"   数据: {json.dumps(data, ensure_ascii=False)}")
    
    resp = requests.post(url, json=payload, timeout=10)
    result = resp.json()
    
    if result.get("errcode") == 0:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest explicitly says operations involving 新增/查询/提醒/通知 should trigger this skill, implying query capability is part of its stated function. However, the CLI only exposes push, notify, and push-and-notify actions, and the code contains no API call or handler for querying smart-sheet records; local deadline lookup is only internal tracking, not user-facing querying of WeCom tables.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code persists full submitted business records, including potentially sensitive reimbursement, banking, personnel, and workflow data, to a local JSON file unrelated to the remote WeCom webhook operation. This expands the data exposure surface: any local user, backup process, log collector, or compromised host can access historical records that users may not expect to be stored locally.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Detailed business records are written locally without warning, disclosure, or configuration control. In this skill context, records may include expense details, payment account information, reviewer identities, and operational task data; silently storing them locally can violate least-privilege and user expectations, and increases privacy/compliance risk.

Ssd 3

Medium
Confidence
96% confidence
Finding
The tracker stores the entire user-submitted data payload under the 'data' field, which may contain highly sensitive financial and personal information such as bank account numbers, payment details, images metadata, and personnel assignments. Persistent plaintext storage greatly increases the blast radius of host compromise, accidental file sharing, backups, and insider access.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The natural-language instructions, feature list, and usage examples are presented exclusively in Chinese, which implicitly forces a specific language for users. There is no opt-in, alternate language guidance, or documented justification that this skill is intended only for a Chinese-speaking or region-specific audience.

Intent-Code Divergence

Low
Confidence
98% confidence
Finding
The first push_to_table definition is documented as '向智能表格推送数据(不含追踪)'. Later in the same file, push_to_table is redefined with a default track=True behavior and writes to the local tracker after successful pushes, which directly contradicts the earlier documented behavior for that function name.

Static analysis

No suspicious patterns detected.