Back to skill

Security audit

Dingtalk Message

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk messaging skill matches its stated purpose, but users should review it because it can reuse stored credentials to send or recall workplace messages, including broad notifications.

Review before installing. Use only with DingTalk apps and webhooks whose permissions are narrowly scoped, avoid all-user sends unless explicitly intended, and treat ~/.dingtalk-skills/config as sensitive because it may contain reusable secrets and tokens. Prefer rotating any credentials that were stored there if access to the machine is shared or uncertain.

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

Warning
Location
SKILL.md:24
Finding
Plaintext Persistence of Reusable DingTalk Credentials and Access Tokens## Vulnerability Details **File Location**: `SKILL.md`, lines 24–28, 35–38, 53–60, and 73–75 **Vulnerability Type**: Plaintext sensitive-data storage **Risk Level**: Medium ### Vulnerable Code ```markdown 2. **读取配置** → 用一条 `grep -E '^KEY1=|^KEY2='` 命令一次性读取该通道所需的全部键值,不要分多次查询。 3. **仅收集该通道所需的缺失配置** → 一次性询问,不要逐条问 4. **持久化** → 写入 config,后续无需再问 ``` ```markdown | Webhook | `DINGTALK_WEBHOOK_URL` | 群设置 → 智能群助手 → 添加自定义机器人 | | Webhook(加签) | 额外 `DINGTALK_WEBHOOK_SECRET` | 创建机器人时选择"加签"模式获得 | | 机器人消息 | `DINGTALK_APP_KEY` + `DINGTALK_APP_SECRET` | 开放平台 → 应用管理 → 凭证信息 | ``` ```bash CONFIG=~/.dingtalk-skills/config # 一次性读取所有所需配置 APP_KEY=$(grep '^DINGTALK_APP_KEY=' "$CONFIG" | cut -d= -f2-) APP_SECRET=$(grep '^DINGTALK_APP_SECRET=' "$CONFIG" | cut -d= -f2-) # Token 缓存:有效期内复用,避免重复请求 CACHED_TOKEN=$(grep '^DINGTALK_ACCESS_TOKEN=' "$CONFIG" 2>/dev/null | cut -d= -f2-) TOKEN_EXPIRY=$(grep '^DINGTALK_TOKEN_EXPIRY=' "$CONFIG" 2>/dev/null | cut -d= -f2-) ``` ```bash sed -i '/^DINGTALK_ACCESS_TOKEN=/d;/^DINGTALK_TOKEN_EXPIRY=/d' "$CONFIG" echo "DINGTALK_ACCESS_TOKEN=$TOKEN" >> "$CONFIG" echo "DINGTALK_TOKEN_EXPIRY=$EXPIRY" >> "$CONFIG" ``` ### Technical Analysis The skill instructs the agent to retain DingTalk application secrets, signing secrets, credential-bearing webhook URLs, and access tokens in `~/.dingtalk-skills/config`. These values constitute reusable authentication material: - `DINGTALK_APP_SECRET` can be used with the application key to obtain access tokens. - `DINGTALK_WEBHOOK_SECRET` permits generation of valid webhook signatures. - `DINGTALK_WEBHOOK_URL` embeds a webhook access token. - `DINGTALK_ACCESS_TOKEN` directly authorizes DingTalk API requests until expiration. The documented workflow does not require restrictive directory or file permissions, ownership validation, a secure credential store, or protection from symbolic-link attacks when editing the configuration file. It also persists short-lived access tokens even though they can be obtained when needed ...[truncated 1688 chars]
Remediation
## Remediation Suggestions 1. Store long-lived credentials in an operating-system keychain, managed secret store, or injected environment variables rather than a shared plaintext configuration file. 2. Do not persist access tokens unless operationally necessary. Obtain them when required and retain them only in process memory. 3. If file-based storage is unavoidable: - Create `~/.dingtalk-skills` with mode `0700`. - Create the configuration file with mode `0600`. - Set `umask 077` before creating temporary or configuration files. - Verify that the file is owned by the current user and is not a symbolic link before reading or modifying it. - Reject files with group or world permissions. 4. Separate non-sensitive configuration from secrets and avoid storing webhook URLs in logs, command histories, or backups. 5. Update credentials atomically through a securely created temporary file rather than direct append operations. 6. Document credential rotation and revocation procedures for application secrets, webhook tokens, and signing secrets. 7. Continue redacting credentials in output, but treat this only as an additional safeguard rather than a replacement for secure storage.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger list includes very broad everyday phrases such as '发消息', '发通知', and 'send message', which can cause this skill to activate in situations where the user did not specifically intend to use DingTalk. Because this skill can send outbound communications and may reuse persisted credentials, accidental invocation can lead to unintended message delivery or disclosure to external recipients.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill instructs the agent to persist credentials and configuration across sessions in a shared local config file, but it does not require clearly informing the user that secrets will be stored locally. This creates a consent and secret-management risk: users may disclose app secrets or webhook credentials without understanding they will be retained and potentially reused by future runs or other related skills.

External Transmission

Medium
Category
Data Exfiltration
Content
if [ -n "$CACHED_TOKEN" ] && [ -n "$TOKEN_EXPIRY" ] && [ "$NOW" -lt "$TOKEN_EXPIRY" ]; then
  TOKEN=$CACHED_TOKEN
else
  RESP=$(curl -s -X POST https://api.dingtalk.com/v1.0/oauth2/accessToken \
    -H 'Content-Type: application/json' \
    -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}")
  TOKEN=$(echo "$RESP" | grep -o '"accessToken":"[^"]*"' | cut -d'"' -f4)
Confidence
60% 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
if [ -n "$CACHED_TOKEN" ] && [ -n "$TOKEN_EXPIRY" ] && [ "$NOW" -lt "$TOKEN_EXPIRY" ]; then
  TOKEN=$CACHED_TOKEN
else
  RESP=$(curl -s -X POST https://api.dingtalk.com/v1.0/oauth2/accessToken \
    -H 'Content-Type: application/json' \
    -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}")
  TOKEN=$(echo "$RESP" | grep -o '"accessToken":"[^"]*"' | cut -d'"' -f4)
Confidence
50% 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
if [ -n "$CACHED_TOKEN" ] && [ -n "$TOKEN_EXPIRY" ] && [ "$NOW" -lt "$TOKEN_EXPIRY" ]; then
  TOKEN=$CACHED_TOKEN
else
  RESP=$(curl -s -X POST https://api.dingtalk.com/v1.0/oauth2/accessToken \
    -H 'Content-Type: application/json' \
    -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}")
  TOKEN=$(echo "$RESP" | grep -o '"accessToken":"[^"]*"' | cut -d'"' -f4)
Confidence
50% 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
if [ -n "$CACHED_TOKEN" ] && [ -n "$TOKEN_EXPIRY" ] && [ "$NOW" -lt "$TOKEN_EXPIRY" ]; then
  TOKEN=$CACHED_TOKEN
else
  RESP=$(curl -s -X POST https://api.dingtalk.com/v1.0/oauth2/accessToken \
    -H 'Content-Type: application/json' \
    -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}")
  TOKEN=$(echo "$RESP" | grep -o '"accessToken":"[^"]*"' | cut -d'"' -f4)
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
这是一个 markdown 文件,因此应检查是否缺少对会影响用户数据或隐私行为的警示。该文档详细说明了批量单聊、群聊发送及已读状态查询,会传输 userId、姓名、消息内容和阅读状态等信息,但未见任何用户提醒或隐私说明。

Missing User Warnings

Medium
Confidence
86% confidence
Finding
工作通知部分说明了 `to_all_user: true` 的全员推送能力,以及通知发送、结果查询和撤回接口,但没有提醒误发、批量影响范围或撤回限制等风险。对于可能广泛影响用户或组织通信的操作,markdown 描述中应提供清晰警示。

Static analysis

No suspicious patterns detected.