Back to skill

Security audit

dingtalk-send-media

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed DingTalk file-sending helper, not a hidden data stealer, but users should verify the file, recipient, and account before using it.

Install only if you want an agent to send local files through DingTalk. Before each use, confirm the exact file path, recipient or group ID, and DingTalk account, especially in multi-account environments. Avoid sending sensitive files unless necessary, use a least-privilege DingTalk app, and do not share unredacted environment or log output containing DINGTALK credentials.

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/send_media.py:334
Finding
Bearer Access Token Exposed in the Media Upload URL<![CDATA[ ## Vulnerability Details **File Location**: `scripts/send_media.py:334-342` **Vulnerability Type**: Bearer token exposure through a URL query parameter **Risk Level**: Medium ### Vulnerable Code ```python url = f"https://oapi.dingtalk.com/media/upload?access_token={access_token}&type={media_type}&robotCode={urllib.parse.quote(robot_code)}" req = urllib.request.Request( url, data=body_data, headers={ 'Content-Type': f'multipart/form-data; boundary={boundary}' } ) ``` ### Technical Analysis The media upload request embeds the DingTalk OAuth access token directly in the URL query string. Although the request uses HTTPS and is sent to an official DingTalk endpoint, TLS only protects the URL while it is in transit. It does not prevent the complete URL from being retained by HTTP client diagnostics, reverse proxies, monitoring systems, exception telemetry, or server-side access logs. Bearer tokens should generally be transported in an authorization header because any party that obtains such a token can use it without additional proof of identity. Placing the token in the URL increases its exposure surface compared with header-based authentication. This behavior supports the Skill's declared DingTalk media-upload functionality and does not indicate deliberate exfiltration to an unrelated service. The issue is the insecure transport location of the credential. ### Attack Path 1. A user invokes the Skill to upload a local media file. 2. The script obtains a DingTalk OAuth access token using the configured client credentials. 3. The script places the token in the media upload URL as `access_token`. 4. A proxy, diagnostic facility, monitoring service, or server access log records the complete request URL. 5. An attacker or unauthorized operator with access to those records extracts the token. 6. The attacker reuses the bearer token against DingTalk APIs before it expires. ### Impact Assessment Successful exploitation could pro ...[truncated 469 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use a DingTalk media upload API that accepts the access token in an authorization header rather than a query parameter. 2. If the legacy endpoint strictly requires a query parameter: - Disable request URL logging for this endpoint. - Add URL-redaction logic that replaces the `access_token` value before logging or reporting errors. - Ensure proxies, telemetry agents, and monitoring systems do not retain query strings. - Keep access-token lifetimes as short as the platform permits. - Grant the DingTalk application only the permissions required for media upload and message sending. 3. Avoid including request URLs in exceptions or debug output. 4. Add tests verifying that tokens never appear in application logs, command output, or returned error objects. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
README.md:115
Finding
Troubleshooting Guidance May Print the DingTalk Client Secret<![CDATA[ ## Vulnerability Details **File Location**: `README.md:115-121` **Vulnerability Type**: Potential secret disclosure through diagnostic output **Risk Level**: Low ### Vulnerable Documentation ```bash # Check whether environment variables are loaded openclaw env | Select-String DINGTALK # Or inspect Gateway logs openclaw logs --grep DINGTALK ``` ### Technical Analysis The documented troubleshooting command filters environment entries containing `DINGTALK` but does not redact their values. If `openclaw env` prints environment-variable values, the output may include `DINGTALK_CLIENTSECRET` and other credential material. The resulting output can be exposed through terminal recordings, screenshots, copied support diagnostics, CI logs, remote support sessions, or shell-output capture. The Gateway log command presents a similar risk if the underlying application logs credential values. Reading DingTalk credentials is necessary for the Skill's declared functionality. Printing their values during configuration verification is not necessary and exceeds the minimum information required to determine whether the variables are configured. ### Attack Path 1. A user configures `DINGTALK_CLIENTSECRET` in the OpenClaw environment. 2. The user follows the README troubleshooting procedure. 3. The diagnostic command prints DingTalk environment-variable names and values. 4. The output is retained in a terminal log, screenshot, support ticket, CI artifact, or shared transcript. 5. An unauthorized party obtains the client ID and client secret from that output. 6. The party requests an access token from DingTalk and exercises the permissions assigned to the application. ### Impact Assessment Disclosure of the client secret could permit unauthorized OAuth token acquisition for the associated DingTalk application. The resulting access would be limited by the application's assigned DingTalk permissions but could persist until the secret is rotated. Unlike an access-t ...[truncated 304 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the diagnostic command with a presence-only check that reports each required variable as `set` or `unset` without printing its value. 2. Explicitly warn users not to paste environment output, credentials, or unredacted Gateway logs into support tickets or chat sessions. 3. Ensure OpenClaw and Gateway logging redact variables whose names contain `SECRET`, `TOKEN`, `PASSWORD`, or similar credential markers. 4. Provide a safe verification utility, for example: ```python import os for name in ("DINGTALK_CLIENTID", "DINGTALK_CLIENTSECRET", "DINGTALK_ROBOTCODE"): print(f"{name}: {'set' if os.environ.get(name) else 'unset'}") ``` 5. Advise users to rotate the DingTalk client secret immediately if it has appeared in logs, screenshots, shell transcripts, or shared diagnostic output. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (16)

Credential Access

High
Category
Privilege Escalation
Content
OpenClaw 会在启动时自动加载此文件中的环境变量。

```bash
# ~/.openclaw/.env
DINGTALK_CLIENTID=dingxxxxxx
DINGTALK_CLIENTSECRET=your_secret
DINGTALK_ROBOTCODE=dingxxxxxx  # 可选,默认同 clientId
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
- `未找到 OpenClaw 配置文件 openclaw.json`:当前无配置文件,需提供环境变量凭证或配置文件
- `未找到钉钉账号配置`:账号自动检测失败,需显式指定账号或补齐配置
- `获取 access token 失败`:检查 `clientId` / `clientSecret`
- `上传媒体文件失败`:检查文件路径、大小、媒体类型和上传权限
- `发送消息失败`:检查目标用户 ID / 群 ID、机器人权限和 `robotCode`
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The README describes how to send local files to DingTalk but does not clearly warn users that the selected file contents and recipient identifiers will be transmitted to an external service. In an agent skill context, this omission can cause unintended data disclosure because a user may not realize that local screenshots, recordings, or attachments are leaving the host environment.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill instructs execution of a local Python script that can read local files, access environment/configured credentials, and send data over the network, but it declares no explicit tool scope or permissions boundary. That creates a confused-deputy risk: an agent may invoke file/network-capable behavior without a machine-readable restriction layer, increasing the chance of unauthorized file exfiltration to DingTalk if user intent or context is misinterpreted.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The script reads ambient configuration and credential sources from the user's environment and home directory to discover DingTalk accounts, which expands its authority beyond the narrowly stated purpose of sending a user-specified local file to a clearly intended DingTalk conversation. In an agent setting, this can cause data to be sent using unintended accounts or hidden credentials without explicit user confirmation, increasing the risk of cross-account data leakage.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The account-selection logic can derive the effective DingTalk account from OPENCLAW_ACCOUNT_ID, OPENCLAW_AGENT_ID, bindings, agent-name suffixes, connector defaults, and other runtime state rather than only from explicit operator intent. In a multi-account environment, this creates a real risk that sensitive files are transmitted through the wrong tenant, bot, or organizational context, which is especially dangerous for a file-sending skill.

External Transmission

Medium
Category
Data Exfiltration
Content
def get_access_token(client_id, client_secret):
    """获取钉钉 access token"""
    url = "https://api.dingtalk.com/v1.0/oauth2/accessToken"
    data = json.dumps({
        'appKey': client_id,
        'appSecret': client_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
def get_access_token(client_id, client_secret):
    """获取钉钉 access token"""
    url = "https://api.dingtalk.com/v1.0/oauth2/accessToken"
    data = json.dumps({
        'appKey': client_id,
        'appSecret': client_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
def get_access_token(client_id, client_secret):
    """获取钉钉 access token"""
    url = "https://api.dingtalk.com/v1.0/oauth2/accessToken"
    data = json.dumps({
        'appKey': client_id,
        'appSecret': client_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.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This code uploads the specified local file to DingTalk and then sends it to a user or group via remote HTTP APIs, but the normal execution path provides no confirmation prompt or user-facing disclosure before transmission. Aside from debug-only output, there is no visible runtime warning about network transfer of potentially sensitive file data and recipient identifiers.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The top-level natural-language documentation and usage descriptions in this file are written exclusively in Chinese, which imposes a specific language on users and maintainers without any opt-in or explanation. Under the stated policy, language constraints should either be optional for the user or clearly justified as region-specific.

Static analysis

No suspicious patterns detected.