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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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

Content
View full analysis

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
View 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.

Content

No source excerpt is available for this finding.

Vague Triggers

High
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 60)May include surrounding context.

md
| 步骤 | 操作 | 执行方式 | 说明 |
|---|---|---|---|
| **① 写入表格** | 构造 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 调群机器人 | 提醒消息发到对应群 |

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 61)May include surrounding context.

md
| 步骤 | 操作 | 执行方式 | 说明 |
|---|---|---|---|
| **① 写入表格** | 构造 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 调群机器人 | 提醒消息发到对应群 |

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 81)May include surrounding context.

}

text

**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" \

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 178)May include surrounding context.

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

prompt 模板:

text

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · SKILL.md (reported line 337)May include surrounding context.

② 写入表格:

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": [{

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
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.

Content

Scanner excerpt · references/wecom_daily_check.py (reported line 71)May include surrounding context.

python
}

    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)} 通知已发送")

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/wecom_smartsheet.py (reported line 258)May include surrounding context.

python
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:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/wecom_smartsheet.py (reported line 301)May include surrounding context.

python
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:

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/wecom_smartsheet.py (reported line 507)May include surrounding context.

python
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:

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.