Back to skill

Security audit

Dingtalk Ai Table Only Curl

Security checks for vulnerabilities and agentic risk

Overview

The skill appears built for legitimate DingTalk AI table work, but it needs Review because it handles live business data, stores credentials/tokens, and includes unsafe shell patterns.

Install only if you trust the DingTalk app credentials being used and are comfortable giving the agent read/write/delete access to the selected AI table. Use least-privilege DingTalk permissions, rotate secrets if exposure is suspected, avoid shared machines, and require explicit confirmation before updates or deletes.

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:84
Finding
Command Injection Through Unescaped Configuration Values<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dt_helper.sh`, lines 84–94; attacker-controlled input enters through lines 343–354 **Vulnerability Type**: Shell command injection through dynamically constructed `sed` expressions **Risk Level**: High ### Vulnerable Code ```bash cfg_set() { local key="$1" local value="$2" mkdir -p "$(dirname "$CONFIG")" touch "$CONFIG" if grep -q "^${key}=" "$CONFIG" 2>/dev/null; then sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" else echo "${key}=${value}" >> "$CONFIG" fi } ``` The untrusted values are supplied by the following command handler: ```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` originate from the command-line argument passed to `--set`. They are embedded directly into a GNU `sed` program without escaping regular-expression metacharacters, replacement metacharacters, delimiters, newlines, or command flags. When a configuration key already exists, a value containing the `|` delimiter can terminate the replacement expression and introduce the GNU `sed` `e` flag. The `e` flag executes the substituted pattern space as a shell command. For example, a value shaped like: ```text $(attacker-command)|e ``` can cause the generated expression to resemble: ```bash sed -i 's|^EXISTING_KEY=.*|EXISTING_KEY=$(attacker-command)|e' "$CONFIG" ``` GNU `sed` then evaluates the replacement result through a shell, causing the injected command substitution to execute. Unvalidated keys also permit regular-expression manipulation and configuration-file corruption. ### Attack Path 1. An attacker identifies or predicts a configuration key that already exists. 2. The attacker convinces the user or an Agent workflow to invoke `dt_helper.sh --set` with a cr ...[truncated 863 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not construct a `sed` program from untrusted input. 2. Restrict keys to an explicit allowlist of supported DingTalk configuration names. At minimum, enforce a pattern such as `^[A-Z][A-Z0-9_]*$`. 3. Update the configuration through a parser that treats keys and values exclusively as data. A safely implemented `awk` rewrite or a structured configuration format is preferable. 4. Write changes to a securely created temporary file and atomically rename it over the original file. 5. Reject values containing NUL bytes or line breaks unless multiline values are explicitly supported. 6. If `sed` remains in use, escape regular-expression syntax in keys and delimiter, backslash, and ampersand characters in replacement values. Do not permit user input to reach command flags. 7. Add regression tests using delimiters, backslashes, ampersands, newlines, command substitutions, and GNU `sed` flags to verify that no input is interpreted as executable syntax. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dt_helper.sh:84
Finding
Plaintext Credentials and Tokens Stored Without Enforced File Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/dt_helper.sh`, lines 10, 84–94, 148–149, and 208–209 **Vulnerability Type**: Insecure storage of sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```bash CONFIG="${DINGTALK_CONFIG:-$HOME/.dingtalk-skills/config}" ``` ```bash cfg_set() { local key="$1" local value="$2" mkdir -p "$(dirname "$CONFIG")" touch "$CONFIG" if grep -q "^${key}=" "$CONFIG" 2>/dev/null; then sed -i "s|^${key}=.*|${key}=${value}|" "$CONFIG" else echo "${key}=${value}" >> "$CONFIG" fi } ``` The same plaintext file is used to persist current and legacy 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 helper stores the DingTalk AppSecret and reusable access tokens in a plaintext `key=value` configuration file. File creation relies on the caller's existing `umask`; the script does not set `umask 077`, apply mode `0600` to the file, or apply mode `0700` to its parent directory. On systems with a common `022` umask, `touch` may create the configuration file with mode `0644`, making it readable by other local users. If the file already exists with permissive permissions, the script also leaves those permissions unchanged. Output masking in `--config` and `--get` does not protect the underlying stored file. The `DINGTALK_CONFIG` environment override can additionally point the storage at another location whose directory permissions or security properties are weaker than those of the user's home directory. ### Attack Path 1. A user runs the helper to save an AppSecret or obtain a DingTalk access token. 2. `cfg_set` creates or updates the plaintext configuration file without enforcing restrictive permissions. 3. Under a permissive process `umask`, or when an existing file is alre ...[truncated 982 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Set `umask 077` before creating the configuration directory or file. 2. Create the parent directory with mode `0700` and enforce mode `0600` on the configuration file after creation and after every replacement. 3. Refuse to use a configuration path that is a symbolic link, is not owned by the current user, or resides in a directory writable by untrusted users. 4. Prefer an operating-system credential store or secret-management service for the AppSecret and reusable tokens. 5. Store non-sensitive settings separately from secrets so ordinary configuration data does not require access to the secret store. 6. Minimize token persistence where practical and clear cached tokens when they are no longer needed. 7. Validate the security of paths supplied through `DINGTALK_CONFIG`. 8. Document token revocation and credential-rotation procedures for suspected file exposure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:31
Finding
Predictable Temporary Script Workflow Enables Local File and Execution Attacks<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 31 **Vulnerability Type**: Unsafe predictable temporary-file handling **Risk Level**: Medium ### Vulnerable Instruction ```text 5. **Execute the operation** → For commands containing variable substitution, pipelines, or multiline logic, write them to `/tmp/<task>.sh` and then execute them with `bash /tmp/<task>.sh`. ``` ### Technical Analysis The Skill instructs the Agent to create executable shell scripts under a predictable `/tmp/<task>.sh` path. It does not require the path to be generated securely, verify file ownership or type, set restrictive permissions, prevent symbolic-link traversal, or remove the script after execution. Shared temporary directories are writable by other local users. Predictable names permit pre-creation and race-condition attacks. Depending on how the Agent's file-writing tool handles existing paths and symbolic links, an attacker may cause the Agent to overwrite another file, write into an attacker-selected target, or execute content that the attacker modifies between creation and invocation. System protections such as sticky-directory semantics or protected-symlink settings may reduce some exploitation variants, but the documented workflow does not rely on or verify those protections and remains unsafe across supported environments. ### Attack Path 1. A local attacker observes or predicts the task name and corresponding `/tmp/<task>.sh` path. 2. Before the Agent creates the script, the attacker creates a conflicting file or symbolic link at that location, or waits for script creation and attempts to modify it before execution. 3. The Agent follows the documented workflow and writes commands to the predictable path without ownership, type, or permission checks. 4. The Agent executes `bash /tmp/<task>.sh`. 5. If the attacker controlled or altered the path or its content, attacker-supplied commands execute with the Agent's privileges. In a symbolic-link over ...[truncated 704 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace predictable paths with a securely generated file: ```bash tmp_script=$(mktemp "${TMPDIR:-/tmp}/dingtalk-task.XXXXXXXX.sh") chmod 700 "$tmp_script" trap 'rm -f -- "$tmp_script"' EXIT HUP INT TERM ``` 2. Verify that the returned path is a regular file owned by the current user before writing or executing it. 3. Quote the temporary path in every operation. 4. Never reuse a caller-supplied or task-derived filename in a shared temporary directory. 5. Set `umask 077` before creating temporary files. 6. Remove temporary scripts immediately after use, including on errors and signals. 7. Avoid embedding access tokens or credentials directly in generated scripts. Pass sensitive values through a protected environment or file descriptor where possible. 8. Update `SKILL.md` so secure temporary-file creation is mandatory rather than optional guidance. ]]>
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 (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented purpose focuses on AI table operations, but the skill behavior also covers credential persistence, token lifecycle management, and identity conversion via helper scripts. This mismatch is dangerous because users and reviewers may authorize the skill for table CRUD while it actually handles secrets and identity data, expanding trust and attack surface beyond the declared function.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly instructs use of shell commands (`bash`, `curl`, temp scripts) but does not declare any tool scope or allowed-tools boundary. That creates an authorization gap where the runtime may permit broader shell use than users or platform policy expect, increasing the chance of unintended command execution or unsafe expansion of capability.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger list contains broad terms like '字段', '记录', and '工作表', which can appear in many unrelated conversations. Overbroad invocation can activate a shell-capable, networked skill unexpectedly, causing accidental access to stored credentials or destructive operations in the wrong context.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill advertises delete and update capabilities for worksheets, fields, and records without warning about irreversible modification risk or requiring explicit confirmation. In this context, the skill operates on live remote data through authenticated API calls, so accidental invocation could directly destroy or alter business data.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The delete-record API is documented without an explicit warning or required user confirmation, unlike the earlier destructive operations for deleting sheets and fields. In an agent skill that can translate natural-language requests into API calls, this increases the risk of accidental or unauthorized destructive actions against user data.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The helper exposes broad DingTalk tenant credential management, token handling, and identity-related operations that exceed the stated AI table purpose. This increases the attack surface and enables reuse of app credentials/tokens for unrelated DingTalk APIs, violating least privilege and making abuse easier if the skill is invoked unexpectedly or composed with other tooling.

External Transmission

Medium
Category
Data Exfiltration
Content
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
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
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}\"}")
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script provides userId↔unionId conversion functions unrelated to AI table CRUD, allowing identity resolution across the enterprise using app credentials. In the context of an AI table skill, this creates unnecessary access to employee identity data and could facilitate enumeration, correlation, or unauthorized lookups of internal users.

External Transmission

Medium
Category
Data Exfiltration
Content
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}\"}")
Confidence
89% confidence
Finding
The request transmits a user identifier to DingTalk's identity lookup API using a reusable tenant token, enabling enterprise identity resolution beyond the skill's AI table scope. In this context, the danger comes from unnecessary personal-data access and capability expansion, not from merely using HTTPS.

External Transmission

Medium
Category
Data Exfiltration
Content
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}\"}")
Confidence
89% confidence
Finding
This call performs the reverse unionId-to-userId lookup, exposing another unnecessary identity-resolution path within an AI table skill. That capability can help correlate internal identities and support directory enumeration or privacy-invasive workflows if misused.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The file header and usage text are written only in Chinese, which imposes a language choice on users without any visible opt-in or alternative locale. Under the policy rule, natural-language instructions that force a specific language can be a locale-policy issue unless the constraint is documented and justified.

Static analysis

No suspicious patterns detected.