Back to skill

Security audit

Dingtalk File Send

Security checks for vulnerabilities and agentic risk

Overview

This skill is for sending files through DingTalk, but it needs review because it can automatically use local DingTalk credentials and upload local files externally with weak account-selection safeguards.

Install only if you are comfortable with an agent using your local OpenClaw DingTalk credentials to upload selected files to DingTalk and send them to specified users. Before use, add or require an explicit confirmation step that displays the file path, recipient user ID, and resolved DingTalk account, and remove the fallback account selection behavior.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:88
Finding

Untrusted Environment Variable Permits DingTalk Account-Binding Bypass

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:88-102 and duplicated in SKILL.md:216-229
Vulnerability Type: Improper authorization and unsafe account selection
Risk Level: High

Vulnerable Code

bash
# Get current agent ID from environment (set by OpenClaw runtime)
AGENT_ID="${OPENCLAW_AGENT_ID:-dingtalk-office}"

# Look up accountId from bindings
ACCOUNT_ID=$(jq -r ".bindings[] | select(.agentId == \"$AGENT_ID\") | .match.accountId" $OPENCLAW_CONFIG)

# Fallback: if no binding found, use agent ID suffix
if [ -z "$ACCOUNT_ID" ] || [ "$ACCOUNT_ID" = "null" ]; then
  # Extract account from agent ID (e.g., "dingtalk-office" → "office")
  ACCOUNT_ID=$(echo "$AGENT_ID" | sed 's/dingtalk-//')
fi

# Read credentials (clientId is used as appKey)
APP_KEY=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientId" $OPENCLAW_CONFIG)
APP_SECRET=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientSecret" $OPENCLAW_CONFIG)
ROBOT_CODE=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].robotCode" $OPENCLAW_CONFIG)

The complete script repeats the same vulnerable selection logic:

bash
# Get current agent ID from environment (set by OpenClaw runtime)
AGENT_ID="${OPENCLAW_AGENT_ID:-dingtalk-office}"

# Look up accountId from bindings
ACCOUNT_ID=$(jq -r ".bindings[] | select(.agentId == \"$AGENT_ID\") | .match.accountId" $OPENCLAW_CONFIG)

# Fallback: if no binding found, use agent ID suffix
if [ -z "$ACCOUNT_ID" ] || [ "$ACCOUNT_ID" = "null" ]; then
  ACCOUNT_ID=$(echo "$AGENT_ID" | sed 's/dingtalk-//')
fi

# Read credentials from OpenClaw config
APP_KEY=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientId" $OPENCLAW_CONFIG)
APP_SECRET=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].clientSecret" $OPENCLAW_CONFIG)
ROBOT_CODE=$(jq -r ".channels.dingtalk.accounts[\"$ACCOUNT_ID\"].robotCode" $OPENCLAW_CONFIG)

Technical Analysis

The skill t ...[truncated 2743 chars]

Remediation
View remediation

Remediation Suggestions

  1. Obtain the active agent identity exclusively from trusted runtime context. Do not use a caller-controlled environment variable as proof of session identity.
  2. Remove the account-name fallback. If no exact authorized binding exists, terminate the operation.
  3. Require the binding to use the DingTalk channel and reject missing, duplicate, empty, or malformed results.
  4. Pass external values to jq with --arg rather than interpolating them into filter source code.
  5. Quote the configuration path consistently and use jq -e so missing configuration entries cause failure.
  6. Validate that the resolved account belongs to the authenticated session before reading credentials or requesting a token.
  7. Consider maintaining an explicit runtime-provided account identifier that cannot be overridden by the skill caller.

A safer binding lookup is:

bash
: "${TRUSTED_AGENT_ID:?Trusted runtime agent identity is required}"

ACCOUNT_ID=$(jq -er --arg agent_id "$TRUSTED_AGENT_ID" '
  [
    .bindings[]
    | select(
        .agentId == $agent_id and
        .match.channel == "dingtalk"
      )
    | .match.accountId
  ]
  | if length == 1 and .[0] != "" then .[0]
    else error("Exactly one authorized DingTalk binding is required")
    end
' "$OPENCLAW_CONFIG") || {
  echo "No unique authorized DingTalk account binding was found."
  exit 1
}

APP_KEY=$(jq -er --arg account_id "$ACCOUNT_ID" \
  '.channels.dingtalk.accounts[$account_id].clientId' \
  "$OPENCLAW_CONFIG") || exit 1

APP_SECRET=$(jq -er --arg account_id "$ACCOUNT_ID" \
  '.channels.dingtalk.accounts[$account_id].clientSecret' \
  "$OPENCLAW_CONFIG") || exit 1

ROBOT_CODE=$(jq -er --arg account_id "$ACCOUNT_ID" \
  '.channels.dingtalk.accounts[$account_id].robotCode' \
  "$OPENCLAW_CONFIG") || exit 1

Apply the correction to both the step-by-step commands and the duplicated complete script.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (19)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

  1. Detect current agentId from session context
  2. Look up binding: agentId → accountId
  3. Read credentials from OpenClaw config by accountId
  4. Get access token
  5. Upload file to DingTalk media server
  6. Send file message to recipient
text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

  1. Detect current agentId from session context
  2. Look up binding: agentId → accountId
  3. Read credentials from OpenClaw config by accountId
  4. Get access token
  5. Upload file to DingTalk media server
  6. Send file message to recipient
text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

  1. Detect current agentId from session context
  2. Look up binding: agentId → accountId
  3. Read credentials from OpenClaw config by accountId
  4. Get access token
  5. Upload file to DingTalk media server
  6. Send file message to recipient
text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

  1. Detect current agentId from session context
  2. Look up binding: agentId → accountId
  3. Read credentials from OpenClaw config by accountId
  4. Get access token
  5. Upload file to DingTalk media server
  6. Send file message to recipient
text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

  1. Detect current agentId from session context
  2. Look up binding: agentId → accountId
  3. Read credentials from OpenClaw config by accountId
  4. Get access token
  5. Upload file to DingTalk media server
  6. Send file message to recipient
text

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

fi

text

### Step 2: Get Access Token

```bash
ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- **Fully automatic** — detects account from current session, no configuration needed
- Media files expire after **30 days** on DingTalk server
- Max file size: **20 MB** for files, **10 MB** for images
- Access token expires after **2 hours**
- Rate limit: ~100 requests/second per app
- Works with any DingTalk account bound in OpenClaw config

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

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

md
- **Fully automatic** — detects account from current session, no configuration needed
- Media files expire after **30 days** on DingTalk server
- Max file size: **20 MB** for files, **10 MB** for images
- Access token expires after **2 hours**
- Rate limit: ~100 requests/second per app
- Works with any DingTalk account bound in OpenClaw config

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The description omits a clear warning that using the skill will upload a local file and recipient identifier to DingTalk servers and will authenticate using locally stored account credentials. In a skill that moves local data off-host, lack of up-front disclosure undermines informed consent and makes accidental data exfiltration more likely.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill advertises broad trigger phrases like 'Share this file with my boss' and 'Forward this document via DingTalk', which can cause the agent to invoke a capability that exfiltrates a local file to an external service without sufficiently explicit user confirmation. Because this skill performs network transmission of user-selected local content and recipient identifiers, overly generic invocation patterns materially increase the chance of unintended disclosure.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This call sends app credentials to DingTalk to obtain an access token, which is an external transmission of sensitive authentication material. While functionally necessary, it is still security-relevant because any unintended invocation causes secrets-backed API activity against a third-party service.

Content

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

Step 2: Get Access Token

bash
ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \
  -H "Content-Type: application/json" \
  -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

This call sends app credentials to DingTalk to obtain an access token, which is an external transmission of sensitive authentication material. While functionally necessary, it is still security-relevant because any unintended invocation causes secrets-backed API activity against a third-party service.

Content

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

Step 2: Get Access Token

bash
ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \
  -H "Content-Type: application/json" \
  -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This request sends a prepared payload to DingTalk containing recipient user IDs and references to uploaded file content, causing external transmission of user data. In context, this is the core exfiltration action of the skill, so accidental or unauthorized invocation could disclose sensitive local files to unintended recipients.

Content

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

md
userIds: [$userId]
  }')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \
  -H "Content-Type: application/json" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \
  -d "$PAYLOAD")

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

This request sends a prepared payload to DingTalk containing recipient user IDs and references to uploaded file content, causing external transmission of user data. In context, this is the core exfiltration action of the skill, so accidental or unauthorized invocation could disclose sensitive local files to unintended recipients.

Content

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

md
userIds: [$userId]
  }')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \
  -H "Content-Type: application/json" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \
  -d "$PAYLOAD")

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The complete script again transmits app credentials to DingTalk for token issuance, making sensitive authentication use available as a copy-pastable automation flow. This increases the operational risk of secret-backed external actions being run without adequate review.

Content

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

md
FILE_EXT="${FILE_NAME##*.}"

# Get access token
ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \
  -H "Content-Type: application/json" \
  -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

External Transmission

Medium
Category
Data Exfiltration
Confidence
89% confidence
Finding

The complete script again transmits app credentials to DingTalk for token issuance, making sensitive authentication use available as a copy-pastable automation flow. This increases the operational risk of secret-backed external actions being run without adequate review.

Content

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

md
FILE_EXT="${FILE_NAME##*.}"

# Get access token
ACCESS_TOKEN=$(curl -s -X POST "https://api.dingtalk.com/v1.0/oauth2/accessToken" \
  -H "Content-Type: application/json" \
  -d "{\"appKey\":\"$APP_KEY\",\"appSecret\":\"$APP_SECRET\"}" | jq -r '.accessToken')

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The complete script's send step transmits recipient identifiers and file message metadata to DingTalk, finalizing delivery of externally uploaded content. Because the skill is marketed as automatic and broadly triggerable, this transmission is especially dangerous if invoked on the wrong file or with the wrong detected account.

Content

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

md
--arg userId "$USER_ID" \
  '{robotCode:$robotCode,msgKey:$msgKey,msgParam:({mediaId:$mediaId,fileName:$fileName,fileType:$fileType}|tojson),userIds:[$userId]}')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \
  -H "Content-Type: application/json" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \
  -d "$PAYLOAD")

External Transmission

Medium
Category
Data Exfiltration
Confidence
95% confidence
Finding

The complete script's send step transmits recipient identifiers and file message metadata to DingTalk, finalizing delivery of externally uploaded content. Because the skill is marketed as automatic and broadly triggerable, this transmission is especially dangerous if invoked on the wrong file or with the wrong detected account.

Content

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

md
--arg userId "$USER_ID" \
  '{robotCode:$robotCode,msgKey:$msgKey,msgParam:({mediaId:$mediaId,fileName:$fileName,fileType:$fileType}|tojson),userIds:[$userId]}')

SEND_RESULT=$(curl -s -X POST "https://api.dingtalk.com/v1.0/robot/oToMessages/batchSend" \
  -H "Content-Type: application/json" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN" \
  -d "$PAYLOAD")

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% 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 318)May include surrounding context.

Check delivery status:

bash
curl -s -X GET "https://api.dingtalk.com/v1.0/robot/oToMessages/status?processQueryKey=$PROCESS_KEY" \
  -H "x-acs-dingtalk-access-token: $ACCESS_TOKEN"

Static analysis

No suspicious patterns detected.