Back to skill

Security audit

Dingtalk Calendar Only Curl

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real DingTalk calendar integration, but it stores powerful enterprise credentials locally and tells the agent to run predictable temporary shell scripts without enough safeguards.

Install only if you are comfortable giving the agent DingTalk app credentials that can modify organizational calendar data. Before use, restrict the DingTalk app scopes to only needed calendar permissions, store the config file in a private 0700 directory with a 0600 file, avoid shared /tmp task scripts, and require explicit confirmation for delete, update, meeting-room removal, sign-in, and sign-out actions.

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:82
Finding

Sensitive DingTalk credentials and tokens are stored without restrictive file permissions

Content
View full analysis

Vulnerability Details

File Location: scripts/dt_helper.sh, lines 82–93
Vulnerability Type: Insecure plaintext credential storage
Risk Level: Medium

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 same function is used to persist reusable 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 contains the DingTalk application secret and reusable OAuth access tokens. The script creates the parent directory and file using mkdir -p and touch, but it does not set or verify restrictive permissions.

File permissions therefore depend entirely on the invoking process's umask. With a common umask of 022, the configuration file can be created with mode 0644, making its contents readable by other local users. The parent directory may similarly be created with mode 0755.

Although display commands partially mask secrets, masking output does not protect the underlying plaintext configuration file. A process that can read the file can recover the complete values.

Attack Path

  1. A user runs dt_helper.sh --set, --token, or --old-token.
  2. The helper creates ~/.dingtalk-skills/config without explicitly restricting its permissions.
  3. The AppSecret or newly issued access token is written to that file in plaintext.
  4. Another local user or compromised process reads the configuration file.
  5. The attacker reuses the AppSecret to request tokens or directly reuses an unexpired cached token agains ...[truncated 853 chars]
Remediation
View remediation

Remediation Suggestions

  1. Set a restrictive umask before creating credential storage:

    bash
    umask 077
    
  2. Create and enforce secure permissions on the directory and file:

    bash
    mkdir -p -m 700 "$(dirname "$CONFIG")"
    touch "$CONFIG"
    chmod 600 "$CONFIG"
    
  3. Verify before every read or write that the configuration path:

    • Is owned by the current effective user.
    • Is a regular file.
    • Is not a symbolic link.
    • Is not readable or writable by group or other users.
  4. Write updates atomically through a securely created temporary file in the same protected directory, then rename it into place.

  5. Prefer an operating-system credential manager or secret service for the AppSecret and reusable tokens.

  6. Avoid persistent access-token caching when operationally feasible. If caching is required, retain only the minimum necessary token lifetime and remove expired credentials promptly.

  7. Document that custom paths supplied through DINGTALK_CONFIG must reside in a private, trusted directory.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:38
Finding

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

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, line 38
Vulnerability Type: Unsafe temporary-file workflow
Risk Level: Medium

Vulnerable Instruction

The execution workflow instructs the agent to write multiline command logic to a predictable task-named path under /tmp and then execute that file:

text
Execute API operations by writing multiline logic to /tmp/<task>.sh and then executing it.

Technical Analysis

/tmp is normally shared and writable by all local users. A path derived from a task name is predictable and is not guaranteed to be unique. The instruction does not require exclusive file creation, ownership validation, symbolic-link rejection, restrictive permissions, or cleanup.

This creates two related attack opportunities:

  • Symlink attack: An attacker pre-creates the anticipated path as a symbolic link. A subsequent write may overwrite the symlink target if the agent has permission.
  • Replacement race: An attacker waits until the agent creates the script and replaces or modifies it before execution.

Because the file is subsequently executed as shell code, successful replacement can lead to arbitrary command execution under the account running the agent.

Attack Path

  1. A local attacker predicts the task-derived filename, such as /tmp/calendar-task.sh.
  2. Before the agent writes the script, the attacker creates that path as a symbolic link to another file writable by the agent; alternatively, the attacker monitors /tmp for creation of the script.
  3. The agent writes API logic to the predictable path without exclusive creation or ownership checks.
  4. In the symlink case, the write affects the linked target. In the replacement case, the attacker swaps or edits the script before execution.
  5. The agent executes the path with its own operating-system privileges.
  6. Attacker-supplied shell commands run in the agent's security context.

Exploitation re ...[truncated 889 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace predictable filenames with mktemp:

    bash
    task_script="$(mktemp "${TMPDIR:-/tmp}/dingtalk-task.XXXXXX")"
    chmod 700 "$task_script"
    trap 'rm -f -- "$task_script"' EXIT HUP INT TERM
    
  2. Verify that the generated path is a regular file, is owned by the current effective user, and is not a symbolic link before writing or executing it.

  3. Keep the temporary file descriptor open from creation through writing where possible, reducing replacement opportunities.

  4. Prefer a private runtime directory owned by the agent and set to mode 0700 instead of a shared /tmp path.

  5. Execute the generated file using its securely retained path and never reconstruct the path from user-controlled task text.

  6. Sanitize all task-derived labels if they are retained for logging; do not incorporate them directly into filesystem paths.

  7. Prefer direct, argument-safe command execution over generating shell scripts when a temporary script is unnecessary.

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 (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is presented as a calendar assistant, but it also manages sensitive credential material and identity conversion flows, including reading/writing AppKey, AppSecret, tokens, and local config state. That hidden expansion of capability increases privilege and attack surface: a user invoking a scheduling action may unknowingly authorize secret handling, token minting, cache manipulation, and identity lookups beyond the declared purpose.

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
86% confidence
Finding

The skill clearly instructs use of shell commands (bash, curl, temp scripts) but does not declare any explicit tool scope or restrictions. This weakens sandboxing and review because a caller may not realize the skill needs code execution and network access, increasing the chance of unintended command execution with local credential access.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger list includes broad everyday terms such as '日历', 'calendar', '会议室', and '忙闲', which can cause accidental routing into a skill that can execute shell commands and call external APIs with stored enterprise credentials. In this context, mis-triggering is more dangerous because invocation is not just informational—it can lead to state-changing calendar actions and use of sensitive 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 74)May include surrounding context.

md
UNION_ID=$(bash "$HELPER" --get DINGTALK_MY_OPERATOR_ID)
CAL_ID="primary"

curl -s -X POST "https://api.dingtalk.com/v1.0/calendar/users/${UNION_ID}/calendars/${CAL_ID}/events" \
  -H "x-acs-dingtalk-access-token: $NEW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"summary":"周会","start":{"dateTime":"2026-03-25T02:00:00.000Z","timeZone":"UTC"},"end":{"dateTime":"2026-03-25T03:00:00.000Z","timeZone":"UTC"}}'

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This documentation explicitly exposes destructive calendar operations such as deleting events without warning that they modify real user data. In an agent skill context, that omission can lead an autonomous system to execute irreversible changes based on ambiguous user prompts or misunderstanding, increasing the risk of unintended data loss.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The sign-in/sign-out operations are documented as simple POST actions without warning that they create real attendance records for meetings. In a tool-using agent, this can cause unintended check-in/check-out actions that affect business records, compliance evidence, or meeting participation tracking.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This shell script contains natural-language guidance, usage text, and warnings exclusively in Chinese, which imposes a specific language on users without offering a choice. The policy specifically calls out language or locale constraints as violations when they are forced without user opt-in or clear justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest describes a DingTalk calendar/scheduling skill focused on calendar CRUD, free/busy, meeting rooms, check-in/out, recurrence, and related calendar features. This helper advertises and implements broader DingTalk platform capabilities such as generic token management for other product domains (todo, docs, AI tables, group messages, work notifications) and userId/unionId identity conversion, which are not justified by the stated calendar-specific purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The manifest frames the skill as a calendar/schedule capability, but the file explicitly supports tokens for all api.dingtalk.com interfaces, old-token access for group messaging/work notifications, and identity conversion endpoints. Those behaviors materially exceed the manifest's described calendar scope, creating a description-to-behavior mismatch at the skill level.

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 74)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
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 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
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 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
79% confidence
Finding

文件主体说明和绝大多数触发条件均固定为中文,仅少量英文别名零散出现,但没有说明是否支持用户以其他语言交互,也未提供语言/地区选择机制。按照语言与 locale 政策,若技能默认强制单一语言而无用户选择,可能构成自然语言策略问题。

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.