Back to skill

Security audit

Dingtalk Contact

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk directory skill is mostly coherent, but it stores credentials and tokens persistently and uses unsafe shell/script patterns around sensitive employee data.

Review before installing. Use only with a least-privilege DingTalk app, avoid shared machines, lock down or replace the plaintext config storage, do not paste untrusted names or IDs into generated shell scripts, and avoid displaying or logging full employee records unless there is a clear business need.

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
scripts/dt_helper.sh:87
Finding

Persistent credentials and access tokens are stored without restrictive file permissions

Content
View full analysis
/dev/null; then sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" else echo "${key}=${value}" >> "$CONFIG" fi } ``` The affected function is used to persist sensitive values, including access tokens: ```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 configuration file stores the DingTalk AppSecret and cached access tokens in plaintext. The script creates the directory and file using `mkdir -p` and `touch`, but does not establish a restrictive `umask` or explicitly apply secure permissions. Consequently, permissions are inherited from the process environment. Under a common `umask` of `022`, a newly created configuration file can be readable by other local users. The masking performed by `--config` and `--get` only affects command output; it does not protect the contents of the file itself. The script also accepts an alternative path through `DINGTALK_CONFIG`. The same insecure creation behavior applies to that path. ### Attack Path 1. A user invokes `--set` to store `DINGTALK_APP_SECRET`, or invokes `--token` or `--old-token`. 2. `cfg_set` creates the configuration file using inherited default permissions. 3. The file receives the application secret and reusable DingTalk access tokens in plaintext. 4. Another local account or compromised process reads the configuration file if its permissions permit access. 5. The attacker submits the stolen credentials or tokens to the documented DingTal ...[truncated 739 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:21
Finding

User-controlled values may be embedded into generated shell source and JSON without safe encoding

Content
View full analysis
.sh` 再 `bash /tmp/.sh` 执行。不要把多行命令直接粘到终端里(终端工具会截断),也不要用 `<<'EOF'` 语法(heredoc 在工具中同样会被截断导致变量丢失) ``` ```bash #!/bin/bash set -e HELPER="/scripts/dt_helper.sh" NEW_TOKEN=$(bash "$HELPER" --token) # api.dingtalk.com 接口用 OLD_TOKEN=$(bash "$HELPER" --old-token) # oapi.dingtalk.com 接口用 # USER_ID=$(bash "$HELPER" --get DINGTALK_MY_USER_ID) # 以当前操作用户为起点时启用 # 在此追加具体 API 调用,例如按姓名搜索用户并获取详情: KEYWORD="张三" SEARCH=$(curl -s -X POST https://api.dingtalk.com/v1.0/contact/users/search \ -H "x-acs-dingtalk-access-token: $NEW_TOKEN" \ -H 'Content-Type: application/json' \ -d "{\"queryWord\":\"$KEYWORD\",\"offset\":0,\"size\":20}") echo "搜索结果: $SEARCH" ``` ### Technical Analysis The Skill directs the Agent to generate shell source under `/tmp` and execute it with Bash. The demonstrated template places a search keyword directly inside a shell assignment and manually interpolates it into JSON. Search keywords and user or department identifiers can originate from user input. If an Agent substitutes such input directly into the generated assignment, shell metacharacters, quotation marks, command substitutions, or line breaks can terminate the intended assignment and introduce executable shell syntax. Even when shell execution is not achieved, manual JSON interpolation does not escape quotation marks, backslashes, control characters, or line breaks according to JSON rules. This can alter the request structure or cause the request to fail. The risk arises from generating executable source code from untrusted values rather than passing those values as inert command arguments or data. ### Attack Path 1. An attacker asks the Skill to search for a contact or department using a cr ...[truncated 1479 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:21
Finding

Predictable scripts in the shared temporary directory permit symlink and replacement attacks

Content
View full analysis
.sh` 再 `bash /tmp/.sh` 执行。不要把多行命令直接粘到终端里(终端工具会截断),也不要用 `<<'EOF'` 语法(heredoc 在工具中同样会被截断导致变量丢失) ``` ### Technical Analysis The Skill recommends writing executable scripts to a predictable `/tmp/.sh` path and later executing that pathname. Shared temporary directories are normally writable by all local users. A task-derived filename may be predictable, and the instructions do not require exclusive file creation, ownership checks, restrictive permissions, symlink rejection, or atomic handling. A local attacker may pre-create the expected path as a symbolic link, potentially causing the Agent to overwrite another file writable by the Agent account. Alternatively, the attacker may replace the script after it is written but before Bash opens it, creating a time-of-check/time-of-use race that can result in execution of attacker-controlled content. ### Attack Path 1. A local attacker predicts or observes the task-based temporary filename. 2. Before the Agent writes the script, the attacker creates a symbolic link at that pathname to another file writable by the Agent; or the attacker waits for script creation. 3. The Agent writes to `/tmp/.sh` without exclusive creation or symlink validation. 4. In the symlink scenario, the linked destination is overwritten with generated script content. 5. In the replacement scenario, the attacker renames or replaces the temporary script before the subsequent `bash /tmp/.sh` operation. 6. Bash opens and executes the attacker's replacement script with the Agent account's privileges. ### Impact Assessment A successful replacement attack enables arbitrary command execution with the privileges of the Agent process. The attacker may read the DingTalk credential file, steal cached ...[truncated 311 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared purpose is contact lookup, but the instructions also cover persistent local configuration management and token retrieval/caching behavior that are not prominently disclosed in the skill description. This mismatch weakens informed consent and can mislead users or orchestrators about secret storage and operational side effects, which is especially risky in a directory skill handling employee data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill clearly directs use of shell and external network calls but does not declare any tool scope such as allowed-tools or permissions. That increases the chance an agent executes powerful shell actions without transparent authorization boundaries, especially since the workflow includes credential handling and script execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill is designed to retrieve employee names, phone numbers, IDs, department paths, and related directory data, but it does not warn that these operations may expose sensitive personal or organizational information. In a contact-directory context, lack of disclosure can lead to overbroad queries and inadvertent privacy violations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The workflow instructs the agent to write AppKey and AppSecret through a helper and states the configuration persists across sessions, but it does not require a clear user warning or consent for long-term secret storage. Persisting credentials without explicit notice increases the risk of unintended retention, later misuse, or compromise on shared systems.

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 41)May include surrounding context.

md
# 在此追加具体 API 调用,例如按姓名搜索用户并获取详情:
KEYWORD="张三"
SEARCH=$(curl -s -X POST https://api.dingtalk.com/v1.0/contact/users/search \
  -H "x-acs-dingtalk-access-token: $NEW_TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{\"queryWord\":\"$KEYWORD\",\"offset\":0,\"size\":20}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

The example places the access token in the URL query string when calling the legacy DingTalk endpoint. Query-string secrets are more likely to leak through logs, proxies, browser/history equivalents, telemetry, or debugging output than header-based credentials.

Content

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

md
echo "搜索结果: $SEARCH"

TARGET_UID=$(echo "$SEARCH" | grep -o '"list":\["[^"]*"' | grep -o '"[^"]*"$' | tr -d '"')
DETAIL=$(curl -s -X POST "https://oapi.dingtalk.com/topapi/v2/user/get?access_token=${OLD_TOKEN}" \
  -H 'Content-Type: application/json' \
  -d "{\"userid\":\"$TARGET_UID\",\"language\":\"zh_CN\"}")
echo "用户详情: $DETAIL"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The document tells users how to obtain and use both new and old DingTalk access tokens but does not warn that these credentials grant access to organizational directory data and must be treated as secrets. Without guidance against exposing tokens in logs, scripts, shell history, or chat responses, the skill materially increases the chance of credential leakage and unauthorized access to employee records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This section documents retrieval of employee PII and employment data, including mobile numbers, email addresses, job numbers, department memberships, and role information, but provides no privacy warning, access-control expectations, or data-minimization guidance. In a skill explicitly designed for directory lookup, this omission increases the risk of over-collection, inappropriate disclosure, and downstream misuse of sensitive organizational personnel data.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script's natural-language interface, including the title, usage/help output, and explanatory text, is entirely in Chinese. This imposes a specific language on users without any opt-in or documented locale constraint, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes a DingTalk contact/directory skill focused on searching users/departments and retrieving contact information. This script additionally exposes generic DingTalk platform token lifecycle management and persistent credential/config storage commands, which are broader platform-administration capabilities rather than contact-query behavior itself.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script allows arbitrary persistent writes to the config file via --set KEY=VALUE without constraining which keys may be modified. In an agent setting, this can let untrusted input persistently alter authentication material, redirect behavior through DINGTALK_CONFIG, or poison future runs by overwriting stored secrets and tokens.

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 41)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 12)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 143)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}\"}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

The script places the access token in the request URL query string when calling the DingTalk API. Query-string tokens can leak through process listings, shell history, proxy logs, monitoring tools, and HTTP client debug output, exposing reusable credentials beyond the intended scope.

Content

Scanner excerpt · scripts/dt_helper.sh (reported line 228)May include surrounding context.

sh
old_token=$(cmd_old_token)

  resp=$(curl -s -X POST \
    "https://oapi.dingtalk.com/topapi/v2/user/get?access_token=${old_token}" \
    -H "Content-Type: application/json" \
    -d "{\"userid\":\"${user_id}\"}")

External Transmission

Medium
Category
Data Exfiltration
Confidence
97% confidence
Finding

As above, the old_token is embedded in the URL query string for the unionId-to-userId lookup. This increases the chance of credential disclosure via local process inspection and infrastructure logs, potentially enabling unauthorized API calls with the leaked token.

Content

Scanner excerpt · scripts/dt_helper.sh (reported line 261)May include surrounding context.

sh
old_token=$(cmd_old_token)

  resp=$(curl -s -X POST \
    "https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=${old_token}" \
    -H "Content-Type: application/json" \
    -d "{\"unionid\":\"${union_id}\"}")

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The example request sets "language":"zh_CN" in the API payload, which forces a specific locale in natural-language content. The file does not state that the locale is optional, user-selected, or required for a region-specific compliance reason.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

Multiple request examples set language to zh_CN, which imposes a specific locale in natural-language-facing API behavior. SQP-3 applies to all file types and flags forced language/locale choices unless the skill offers opt-in or clearly justifies the locale constraint; this document does neither.

Content

No source excerpt is available for this finding.