Back to skill

Security audit

Dingtalk CLI SKILL

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk automation skill is broadly useful but should be reviewed carefully because it grants extensive business-data and message-sending authority with inconsistent safeguards.

Install only if you trust the publisher and the DingTalk app scopes being granted. Prefer the pinned release with hash verification over the mutable installer, avoid using it on shared machines, keep client secrets and webhook tokens out of chat/logs/shell history, and require explicit confirmation before approvals, deletes, message sends, paid DING calls, room bookings, or file uploads.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Warning
Location
README.md:15
Finding

Mutable Remote Installer Downloads and Executes a Privileged External CLI

Content
View full analysis

Vulnerability Details

File Location: README.md:15-25; related binary installation configuration at SKILL.md:8-24
Vulnerability Type: Remote payload retrieval and execution
Risk Level: Medium

Vulnerable Code

powershell
# Step 1: Download the installation script locally
$scriptPath = "$env:TEMP\install_dws.ps1"
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1" -OutFile $scriptPath -UseBasicParsing

# Step 2: Open and inspect it
notepad $scriptPath

# Step 3: Execute it after deciding that it is trustworthy
& $scriptPath

The Skill also declares a precompiled executable as a required dependency:

yaml
requires:
  bins:
    - dws
  env:
    - DWS_CLIENT_ID
    - DWS_CLIENT_SECRET
    - DWS_CONFIG_DIR
    - DWS_SERVERS_URL
install:
  - kind: url
    url: https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli/releases/download/v1.0.8/dws-windows-amd64.zip
    bins:
      - dws.exe
    verify:
      sha256: 7dc4e568b1386423784e6baf17fe675c11eb6c075bd887dcb0ede53cdded85e8

Technical Analysis

The documented installation process downloads PowerShell code from the mutable main branch of an external GitHub repository and subsequently executes it. Although the README tells the user to inspect the file first, this is a manual control and does not cryptographically bind execution to the version reviewed during this audit.

The installed dws executable is the central implementation of the Skill and is not included in the audited package. It is expected to receive OAuth state or application credentials and perform operations across contacts, calendars, chat, attendance, reports, approvals, todos, and AI tables. Consequently, compromise of the remote repository, its release account, or its installation script could change the effective payload after this Skill has been reviewed.

The ...[truncated 1784 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin the PowerShell installer URL to an immutable Git commit rather than the main branch.
  2. Publish a SHA-256 digest and a cryptographic signature for the installer, and verify both before execution.
  3. Make verification mandatory and fail closed if the digest or signature does not match.
  4. Pin every documented download to a specific release artifact; do not direct users to releases/latest for security-sensitive installation.
  5. Publish the CLI source, reproducible-build instructions, signed checksums, and provenance attestations so the executable can be independently verified.
  6. Vendor or include the exact reviewed installer source in the Skill package.
  7. Request only the DingTalk scopes required for each operation and separate read-only from mutating capabilities where possible.
  8. Align the Skill version, _meta.json version, downloaded CLI version, and documentation to prevent ambiguity about which component was reviewed.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/upload_attachment.py:67
Finding

Attachment Contents Can Be Uploaded to an Unvalidated Destination URL

Content
View full analysis

Vulnerability Details

File Location: scripts/upload_attachment.py:67-74, with the untrusted URL obtained and propagated at scripts/upload_attachment.py:124-145
Vulnerability Type: Unrestricted sensitive-data transmission destination
Risk Level: Medium

Vulnerable Code

python
def upload_to_oss(upload_url: str, file_path: Path, mime_type: str) -> bool:
    """Upload a file to OSS through HTTP PUT."""
    file_data = file_path.read_bytes()
    req = Request(upload_url, data=file_data, method='PUT')
    req.add_header('Content-Type', mime_type)

    try:
        with urlopen(req, timeout=120) as resp:

The destination is taken directly from the external CLI response:

python
result = run_dws(dws_args)
if not result:
    return None

status = result.get('status', '')
if status != 'success':
    error = result.get('error', {})
    print(f"Error preparing upload: {error.get('message', json.dumps(error, ensure_ascii=False))}", file=sys.stderr)
    return None

data = result.get('data', {})
upload_url = data.get('uploadUrl', '')
file_token = data.get('fileToken', '')

if not upload_url or not file_token:
    print(f"Response is missing uploadUrl or fileToken: {json.dumps(data, ensure_ascii=False)}", file=sys.stderr)
    return None

if not upload_to_oss(upload_url, file_path, mime_type):
    return None

Technical Analysis

Uploading an explicitly selected attachment is necessary for the declared AI-table attachment feature. The vulnerability is not the upload itself, but the absence of destination validation.

The script trusts uploadUrl returned by dws and submits the entire selected file with an HTTP PUT. It does not require HTTPS, verify that the hostname belongs to DingTalk or an approved Alibaba OSS domain, restrict the destination port, reject embedded credentials, or explicitly validate redirect destinations.

The script also resolves and reads ...[truncated 1630 chars]

Remediation
View remediation

Remediation Suggestions

  1. Parse the URL before use and permit only https destinations.
  2. Maintain an explicit allowlist of documented DingTalk or Alibaba OSS hostnames and approved hostname suffixes.
  3. Reject nonstandard ports, embedded credentials, malformed hostnames, IP-literal destinations, and unsupported URL schemes.
  4. Disable redirects for upload requests where feasible. If redirects are required, validate the scheme, hostname, and port of every redirect target before transmitting file contents.
  5. Restrict attachment paths to OPENCLAW_WORKSPACE by default, using the same containment approach implemented in import_records.py and bulk_add_fields.py.
  6. Require explicit user confirmation before uploading files outside the configured workspace or files likely to contain credentials.
  7. Consider streaming the file rather than loading up to 100 MB completely into memory.
  8. Resolve dws from a trusted, fixed path and verify the executable identity before trusting upload authorization responses.
  9. Avoid logging complete presigned URLs because query parameters may contain temporary authorization material.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (56)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

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

md
---
name: dingtalk-dws
description: "钉钉 CLI 技能 / 钉钉 dingding / 钉钉 dws skill / 管理钉钉全部产品:AI表格、日历、通讯录、群聊机器人、待办、审批、考勤、日报周报、DING消息、工作台。Manage DingTalk products (AI forms, calendar, contacts, bots, todos, approvals, attendance, reports, DING, workbench)"
version: "1.0.9"

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 · references/global-reference.md (reported line 23)May include surrounding context.

md
| Token | 有效期 | 说明 |
|-------|--------|------|
| Access Token | 2 小时 | 调用 API 的凭证,过期自动刷新 |
| Refresh Token | 30 天 | 换新 Access Token,使用后轮转 |

30 天内使用一次即自动续期。

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 · references/global-reference.md (reported line 24)May include surrounding context.

md
| Token | 有效期 | 说明 |
|-------|--------|------|
| Access Token | 2 小时 | 调用 API 的凭证,过期自动刷新 |
| Refresh Token | 30 天 | 换新 Access Token,使用后轮转 |

30 天内使用一次即自动续期。

Vague Triggers

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The intent-matching section uses very broad natural-language triggers such as '日程/会议/约会/日历', '查看', '创建', and '删除', which can overlap with ordinary conversational text and cause the agent to invoke calendar actions when the user did not clearly request a tool operation. In a skill that includes state-changing commands like create, update, delete, participant changes, and room booking, ambiguous triggering materially raises the risk of unintended modifications to calendar data.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill documents high-impact workflow actions—approve, reject, and revoke—without any mention of confirmation, authorization checks, or safety guardrails. Because these commands alter business process state, an agent using this reference could perform irreversible or sensitive actions based on misinterpretation, prompt injection, or incomplete context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill explicitly instructs users to run an authentication flow and states that credentials persist for 30 days, while the metadata also requires client secrets in environment variables. That creates meaningful risk of credential mishandling, reuse on shared systems, or unintended exposure, especially because the documentation gives no warning about secure storage, shared-machine use, or secret redaction.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documented command can send messages to a DingTalk group, which is an external side effect affecting real organizational communications. Without any warning, confirmation guidance, or scope limitation, a user or downstream agent could spam groups, send misleading content, or message the wrong audience using valid credentials.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file title and instructional content are entirely in Chinese and direct agents to consult this document for error handling. Because the skill does not offer an alternative language or note that it is intentionally limited to a Chinese-speaking environment, this can violate the language/locale policy requiring user opt-in or clear justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The document instructs users to export DWS_CLIENT_ID and DWS_CLIENT_SECRET in headless environments but does not warn that secrets placed in shell commands, CI variables, logs, or shared runners can be exposed to other users or retained in history. This is a real security weakness in operational guidance because it encourages handling long-lived client credentials in a way that can lead to credential disclosure.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The intent mapping uses broad natural-language triggers such as “打卡记录/出勤/考勤” and “排班/班次/当班”, which can overlap with ordinary conversation and cause the agent to invoke attendance commands without sufficiently precise user intent. In this context, the commands expose employee attendance records, schedules, and rule information, so a false trigger could lead to unintended access or disclosure of HR-related personal data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation exposes destructive operations such as event deletion, participant removal, and room unbooking without prominently warning that they modify persistent scheduling data. If an agent follows these references directly, a user or ambiguous prompt may trigger irreversible or disruptive changes without sufficient awareness or confirmation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documentation instructs users to send messages using a Webhook token but does not warn that the token is a credential that grants message-sending capability. If users expose the token in prompts, logs, screenshots, shell history, or shared examples, an attacker could reuse it to send spoofed messages, alerts, or spam into organizational chats.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The intent mapping uses very broad natural-language triggers such as "我是谁/我的信息", "找人/搜人", and "哪个部门", which can cause the agent to invoke contact lookups from casual conversation rather than an explicit user request to access directory data. In a contact/employee-directory skill, unintended invocation can expose personal or organizational information such as user IDs, org email addresses, department IDs, and member lists, especially because the workflow explicitly encourages passing these identifiers into other products.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill maps very broad natural-language triggers like “DING 一下”, “紧急通知”, and especially “电话提醒” directly to a command that can send urgent notifications, including paid SMS/call variants. Because these phrases lack scope constraints, an agent could over-trigger high-impact actions from ambiguous user input, causing spam, unwanted escalation, or financial cost.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation describes creating reports and optionally sending them to chat recipients or specific user IDs, but does not instruct the agent to warn the user that content may be delivered to other people. In an agent setting, this increases the chance of unintended disclosure of sensitive business information through an easy-to-trigger write/send workflow.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

该 markdown 文件在“意图判断”中使用了“查日志/看日报”“写日报/发日志/填日志”等自然语言短语作为触发示例,但未提供边界、限定上下文或排除条件。这些短语在普通对话中较常见,且文档没有说明何时应触发 report 技能、何时不应触发,存在误调用风险。

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The intent mapping uses broad natural-language triggers such as “审批/请假/报销/出差” and “同意审批/批准”, which can overlap with ordinary conversation and cause the agent to invoke sensitive approval actions without sufficiently specific user intent. In a skill that exposes business workflow operations, ambiguous triggering increases the risk of unintended state-changing actions against approval records.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation includes an irreversible delete operation and only later notes that confirmation is recommended, rather than making a mandatory, explicit precondition before deletion. In agentic use, this can normalize destructive execution paths and lead to accidental permanent deletion if a user utterance is misinterpreted or the '--yes' flag is applied automatically.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The intent-matching phrases are broad and overlap with ordinary conversational language such as '记一下' or '看看待办', which can cause the agent to invoke todo actions without sufficiently explicit user intent. In an action-taking skill, this increases the risk of unintended task creation, modification, or disclosure of personal task data, especially if the system relies heavily on phrase matching rather than confirmation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The intent mapping uses short natural-language phrases like "看看应用" and "应用详情", which are common conversational expressions and do not define clear boundaries for when this skill should activate. The file also does not provide exclusion conditions or negative examples to distinguish workbench-specific requests from ordinary discussion about apps.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The recovery guide is written entirely in Chinese and provides operational instructions only in that language. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The module docstring and usage text are entirely in Chinese, and the tool's user-facing interface is also described only in Chinese. This imposes a specific language on users without offering an opt-in, choice, or documented region-specific justification, which matches the language/locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code file contains natural-language instructions and messages that force a specific language/locale for all users. The policy permits locale constraints only when the skill offers a choice or clearly documents a justified region-specific requirement, which is not present here.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/attendance_my_record.py (reported line 30)May include surrounding context.

python
print(f"[dry-run] {' '.join(cmd)}")
        return None
    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=60
        )
        if result.returncode != 0:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/attendance_team_shift.py (reported line 28)May include surrounding context.

python
print(f"[dry-run] {' '.join(cmd)}")
        return None
    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True, timeout=60
        )
        if result.returncode != 0:

Static analysis

No suspicious patterns detected.