Back to skill

Security audit

Dingtalk Document

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk document skill is mostly coherent, but it stores sensitive credentials persistently and includes an unsafe configuration-writing helper that can enable local command execution from crafted input.

Install only after the helper is fixed to validate allowed config keys, reject control characters, avoid sed interpolation, and store secrets with owner-only permissions or a credential store. Until then, avoid using this skill with real DingTalk app secrets or accounts that can delete documents or change member permissions.

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

Warning
Location
scripts/dt_helper.sh:79
Finding

Insecure File Permissions for Stored DingTalk Credentials and Access Tokens

Content
View full analysis
/dev/null; then sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" else echo "${key}=${value}" >> "$CONFIG" fi } ``` ```bash cfg_set DINGTALK_ACCESS_TOKEN "$token" cfg_set DINGTALK_TOKEN_EXPIRY "$((now + expire_in - 200))" ``` ```bash cfg_set DINGTALK_OLD_TOKEN "$token" cfg_set DINGTALK_OLD_TOKEN_EXPIRY "$((now + expires_in - 200))" ``` ### Technical Analysis The helper stores the DingTalk application secret and reusable access tokens in a plaintext configuration file. When the file and its parent directory are created, the script does not set a restrictive `umask`, assign explicit permissions, or verify the security of an existing configuration path. Consequently, the effective permissions depend on the environment in which the script runs. For example, under a conventional `umask 022`, `touch "$CONFIG"` can create a file readable by other local users. The parent directory may likewise be created without owner-only access. The stored values include: - `DINGTALK_APP_SECRET` - `DINGTALK_ACCESS_TOKEN` - `DINGTALK_OLD_TOKEN` These values can authorize calls to DingTalk document, workspace, contact, or other APIs according to the permissions granted to the application. ### Attack Path 1. A user or Agent invokes `dt_helper.sh --set` or a token command in an environment with permissive default file-creation permissions. 2. `cfg_set` creates `$HOME/.dingtalk-skills/config` using `touch`, without applying owne ...[truncated 1153 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dt_helper.sh:79
Finding

Command Execution Through Unsanitized Input Embedded in a sed Program

Content
View full analysis
/dev/null; then sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" else echo "${key}=${value}" >> "$CONFIG" fi } ``` The `--set` handler accepts unrestricted keys and values and passes them directly to `cfg_set`: ```bash cmd_set() { local kv="$1" if [ -z "$kv" ] || [[ "$kv" != *"="* ]]; then echo "❌ 格式错误,用法: --set KEY=VALUE" >&2 exit 1 fi local key="${kv%%=*}" local value="${kv#*=}" cfg_set "$key" "$value" echo "✅ 已设置 ${key}" } ``` ### Technical Analysis Both `key` and `value` are attacker-controlled input to the `--set` command. They are inserted into a GNU `sed` substitution without escaping: ```bash sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" ``` This creates several injection primitives: - The key is interpreted as a regular expression. - The value is interpreted as a sed replacement. - A pipe character can terminate the replacement section. - Newline characters can introduce additional sed commands. - On GNU sed, the `e` substitution flag executes the resulting replacement text through a shell. Shell metacharacters contained in an ordinary variable are not re-evaluated directly by Bash during expansion. However, the injected GNU sed `e` flag creates a separate command-execution stage, allowing the substituted output to be interpreted by a shell. The vulnerable update branch is reached when the supplied key already exists in the configuration. An attacker able to invoke `--set` can first create a benign entry and then update it with a malicio ...[truncated 2150 chars]
Remediation
View remediation
&2 exit 1 ;; esac ``` 2. Reject control characters, especially carriage returns and newlines, in both keys and values. 3. Do not interpolate input into a sed program. Replace the implementation with a parser that compares keys as literal strings and writes an atomic replacement file. For example, use `awk` with values passed through environment variables or file descriptors rather than embedded into source text, while still validating newlines and key syntax. 4. If sed must be retained: - Escape regular-expression metacharacters in the key. - Escape `&`, backslashes, and the selected delimiter in the replacement value. - Reject all newline characters. - Do not rely on escaping alone where GNU sed's `e` extension is available. 5. Use a protected temporary file in the same directory, verify successful output, set mode `600`, and atomically rename it into place. 6. Add regression tests covering delimiters, backslashes, ampersands, newlines, sed flags, regular-expression characters, and shell metacharacters. ]]>
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 (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill description claims document-management functionality, but the behavior described includes undeclared configuration management, token acquisition/caching, and identity conversion. This mismatch obscures the true security-sensitive capabilities of the skill, making users and reviewers less likely to recognize that it can handle secrets, persist credentials, and perform privileged actions.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
> `dt_helper.sh` 位于本 `SKILL.md` 同级目录的 `scripts/dt_helper.sh`。

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill instructs use of shell commands but does not declare any tool scope or allowed-tools boundary. This weakens least-privilege controls and makes it harder for the runtime or reviewer to constrain execution, increasing the risk of unintended command execution or credential handling through shell access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger description uses broad phrases such as general references to documents and knowledge bases, which can cause accidental invocation in normal conversation. In a skill that can read, write, delete, and modify member permissions, mis-triggering materially raises the chance of unintended sensitive operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill documentation omits clear risk disclosures for write, delete, and member-permission management actions. Without prominent warnings and confirmation requirements, users may not appreciate that the skill can alter data or access control, increasing the risk of accidental destructive or privilege-changing operations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation exposes a destructive delete capability for documents but does not include any explicit user-confirmation, recovery, or safety guidance, even though nearby write operations do include stronger warnings. In an agent skill context, this increases the chance that an automated workflow or prompt misunderstanding could irreversibly delete user data without adequate friction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file’s natural-language interface, including the title, help output, and usage guidance, is entirely in Chinese. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the skill clearly documents a justified region-specific constraint, which this file does not.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The helper advertises and implements generic DingTalk credential management for multiple API domains, plus configuration persistence for app secrets and tokens, which exceeds the stated document/knowledge-base scope. This overbroad capability increases attack surface and makes credential misuse easier if the skill is invoked in unintended contexts or chained with other actions.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 60)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 13)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 49)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 60)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 98)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 109)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 128)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 167)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 178)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 209)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 231)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 245)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 269)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 283)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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.md (reported line 292)May include surrounding context.

md
fi

  # 过期或无缓存,重新获取
  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}\"}")

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

sh
fi

  # 过期或无缓存,重新获取
  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}\"}")

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/dt_helper.sh (reported line 129)May include surrounding context.

sh
fi

  # 过期或无缓存,重新获取
  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}\"}")

Static analysis

No suspicious patterns detected.