Back to skill

Security audit

Dingtalk Workspace

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk automation skill is mostly coherent, but it should go to Review because it includes unsafe installer commands and examples/scripts that can approve or mutate enterprise data without a strong confirmation boundary.

Review this before installing in a real enterprise workspace. Prefer a verified release or pinned source build, avoid the pipe-to-shell installer examples, use least-privilege DingTalk OAuth credentials, do not put real client secrets in shell history or shared logs, and require human review before approvals, deletes, bulk imports, group changes, or message sends. Treat bundled scripts as applying changes by default unless you explicitly use dry-run behavior.

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

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:42
Finding
Unverified Remote Installer Is Executed Directly from a Mutable Branch<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:42-49` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Vulnerable Code ```bash **Option 3: Install script (review first!)** ```bash # macOS / Linux - REVIEW SCRIPT BEFORE RUNNING curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh # Windows (PowerShell) - REVIEW SCRIPT BEFORE RUNNING irm https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1 | iex ``` ``` ### Technical Analysis The installation instructions retrieve scripts from the mutable `main` branch of an external GitHub repository and immediately pass the downloaded content to a shell or PowerShell interpreter. No immutable commit, release version, cryptographic hash, or signature is verified before execution. The comments instructing users to review the script do not create an actual review boundary because the commands themselves perform retrieval and execution as one operation. Even if the installer was safe when this Skill was audited, its effective payload can change afterward. This creates a supply-chain trust dependency on the external repository, its maintainers, their accounts, GitHub infrastructure, and the integrity of the repository's default branch. ### Attack Path 1. An attacker compromises the external repository, a maintainer account, or a publishing token. 2. The attacker modifies `scripts/install.sh` or `scripts/install.ps1` on the `main` branch. 3. A user or autonomous Agent follows the installation instructions. 4. `curl | sh` or `irm | iex` retrieves and immediately executes the modified payload. 5. The payload runs with the permissions of the user performing the installation. 6. It can subsequently steal credentials, alter local files, establish persistence, or replace the installed `dws` executable. ### Impact Assessment Successful exploitation provides arbitrar ...[truncated 658 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all `curl | sh` and `irm | iex` installation instructions. 2. Pin downloads to an immutable, reviewed release version or commit rather than `main`. 3. Download the installer as a separate file without executing it: ```bash curl -fL -o install.sh https://example.invalid/path/to/pinned/install.sh ``` 4. Publish and require verification of a SHA-256 checksum or cryptographic signature: ```bash echo "<expected-sha256> install.sh" | sha256sum --check - ``` 5. Require users to inspect the locally downloaded script before explicitly running it: ```bash less install.sh sh install.sh ``` 6. Prefer reproducible builds from a pinned source tag or signed release artifacts. 7. Document the expected files, network endpoints, and filesystem changes made by the installer. 8. Avoid recommending elevated execution unless a specific operation strictly requires it. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/products/oa.md:82
Finding
Approval Workflow Authorizes Expenses Using Only Attacker-Influenced Title Text<![CDATA[ ## Vulnerability Details **File Location**: `references/products/oa.md:82-91` **Vulnerability Type**: Unsafe automated authorization and confirmation bypass **Risk Level**: High ### Vulnerable Code ```bash ### Auto-Approve Low-Value Requests ```bash # Get pending approvals dws oa approval list --status pending --jq '.result[] | select(.title | contains("Expense")) | .instanceId' # Approve each for inst in $INSTANCES; do dws oa approval approve --instance-id "$inst" --comment "Auto-approved" --yes done ``` ``` ### Technical Analysis The workflow is described as approving “low-value” requests, but it does not inspect any structured monetary amount, currency, applicant identity, cost center, policy result, or approval details. Selection is based only on whether the request title contains the string `Expense`. Approval titles may be controlled or influenced by request applicants. Consequently, title matching is not an authorization control and does not establish that a request is low value or policy compliant. The loop then appends `--yes`, bypassing interactive confirmation for every selected instance. This converts an insufficient text filter into an automated privileged enterprise decision. ### Attack Path 1. An attacker or untrusted employee submits an expense approval request. 2. The attacker includes `Expense` in the request title while specifying an unauthorized amount or other harmful details. 3. A privileged user or Agent runs the documented auto-approval workflow. 4. The title filter selects the attacker's approval instance without validating its amount or contents. 5. The loop invokes `dws oa approval approve` with `--yes`. 6. The request is approved under the authenticated approver's authority without meaningful review. ### Impact Assessment Successful exploitation can cause unauthorized enterprise approvals, including potentially fraudulent expenses. The exact financial and organizational impact depends on the OAuth identity's ap ...[truncated 514 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the auto-approval example or require explicit human confirmation for every approval instance. 2. Never authorize an approval based on title text. 3. Retrieve and validate complete structured approval details before taking action. 4. Enforce an explicit allowlist of process identifiers, applicants, cost centers, currencies, and permitted request types. 5. Validate the actual numeric amount against a centrally configured policy threshold. 6. Reject or defer processing when required fields are absent, malformed, or ambiguous. 7. Use `--dry-run` to display the exact operation before execution. 8. Do not append `--yes` to approval or rejection commands in automated guidance. 9. Record the validated policy inputs and require an auditable human authorization step before execution. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/calendar_schedule_meeting.py:27
Finding
Mutation Scripts Skip Confirmation and Execute Bulk Changes by Default<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/calendar_schedule_meeting.py:27-40` - `scripts/todo_batch_create.py:14-26` - `scripts/import_records.py:14-21` **Vulnerability Type**: Unsafe default execution and confirmation bypass **Risk Level**: Medium ### Vulnerable Code `scripts/calendar_schedule_meeting.py`: ```python def run_dws_action(args, dry_run=False): """Run dws action command.""" cmd = ["dws"] + args if dry_run: cmd.append("--dry-run") else: cmd.append("--yes") result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"Error: {result.stderr}", file=sys.stderr) return False print(result.stdout) return True ``` `scripts/todo_batch_create.py`: ```python def run_dws(args, dry_run=False): """Run dws command.""" cmd = ["dws"] + args if dry_run: cmd.append("--dry-run") else: cmd.append("--yes") result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"Error: {result.stderr}", file=sys.stderr) return False print(result.stdout) return True ``` `scripts/import_records.py`: ```python def run_dws(args): """Run dws command.""" cmd = ["dws"] + args + ["--yes"] result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"Error: {result.stderr}", file=sys.stderr) return False return True ``` ### Technical Analysis These scripts append `--yes` whenever the caller does not explicitly request a dry run. As a result, their default behavior is to perform enterprise mutations while bypassing the CLI's confirmation mechanism. This conflicts with the Skill's stated security requirement to always use `--dry-run` before mutation operations. The risk is amplified for batch todo creation and CSV import because a single invocation may create an arbitrary number of remote objec ...[truncated 1672 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make dry-run behavior the default for every mutation script. 2. Replace opt-in `--dry-run` with an explicit execution flag such as `--apply`. 3. Require a successful preview before accepting `--apply`. 4. Do not automatically append `--yes`; preserve an interactive confirmation unless a separately authorized automation mode is explicitly enabled. 5. Before bulk operations, display the target workspace, object count, recipients, and a sanitized sample. 6. Require confirmation of the total operation count. 7. Add configurable maximum item limits and reject unexpectedly large input files. 8. Add fail-fast behavior and an optional rollback or cleanup plan where supported. 9. For meetings, verify availability and room identity before creating the event. 10. For CSV and JSON imports, validate schemas, field lengths, recipient identifiers, and target IDs before any remote write. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:54
Finding
OAuth Client Secrets Are Passed Through Command-Line Arguments<![CDATA[ ## Vulnerability Details **File Locations**: - `SKILL.md:54-59` - `references/global-reference.md:24-33` - `references/error-codes.md:23-27` **Vulnerability Type**: Insecure credential handling **Risk Level**: Medium ### Vulnerable Code `SKILL.md`: ```bash # First-time login (credentials saved to system Keychain) dws auth login --client-id <your-app-key> --client-secret <your-app-secret> # Or via environment variables export DWS_CLIENT_ID=<your-app-key> export DWS_CLIENT_SECRET=<your-app-secret> dws auth login ``` `references/global-reference.md`: ```bash # 3. Login with credentials dws auth login --client-id <app-key> --client-secret <app-secret> ``` ```bash export DWS_CLIENT_ID=<app-key> export DWS_CLIENT_SECRET=<app-secret> dws auth login ``` `references/error-codes.md`: ```bash # Re-authenticate dws auth login --client-id <app-key> --client-secret <app-secret> ``` ### Technical Analysis The documentation encourages users to place an OAuth client secret directly in a command-line argument. Once substituted with a real value, the secret may be retained in shell history and may be visible to process-monitoring tools, diagnostics, terminal recordings, or command auditing systems. The alternative environment-variable method avoids placing the value in the immediate command line but still exposes the secret to the process environment and potentially to inherited child processes, debug output, crash reports, or deployment logs. Saving the resulting credentials to a system keychain after authentication does not prevent exposure that occurs while the initial command is entered and executed. ### Attack Path 1. A user follows the documented authentication example and replaces the placeholder with a real client secret. 2. The command is recorded in shell history, terminal logs, process telemetry, or an automation transcript. 3. Another local user, support operator, log reader, or compromised process obtains the secret. 4. The attacker combines t ...[truncated 763 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove examples that pass client secrets as command-line arguments. 2. Implement an interactive, no-echo secret prompt in `dws auth login`. 3. Prefer OAuth device authorization or another flow that does not require users to handle a long-lived client secret directly. 4. Where interactive entry is unavailable, accept the secret through a protected file descriptor, operating-system credential store, or restricted secret manager integration. 5. Ensure secrets are redacted from debug logs, errors, telemetry, crash reports, and command transcripts. 6. Warn users not to place secrets in shell history, scripts, CI command strings, or plaintext configuration files. 7. If environment variables must be supported, document their inheritance and logging risks, unset them immediately after authentication, and prevent unnecessary child processes from inheriting them. 8. Rotate any credential suspected of having appeared in process listings, shell history, or logs. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (32)

Chaining Abuse

High
Category
Tool Misuse
Content
```bash
# macOS / Linux - REVIEW SCRIPT BEFORE RUNNING
curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.sh | sh

# Windows (PowerShell) - REVIEW SCRIPT BEFORE RUNNING
irm https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install.ps1 | iex
Confidence
97% confidence
Finding
Piping fetched network content into a shell is a dangerous command-chaining pattern because it grants immediate code execution to unverified remote content. In this skill context, the danger is elevated because installation is a prerequisite to using a high-privilege enterprise workspace tool, making compromise of the installer a viable path to credential theft or broader host compromise.

Credential Access

High
Category
Privilege Escalation
Content
### Authentication

```bash
# First-time login (credentials saved to system Keychain)
dws auth login --client-id <your-app-key> --client-secret <your-app-secret>

# Or via environment variables
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Instruction Override

High
Category
Prompt Injection
Content
### Step 1: Identify Error Type

```bash
# Enable debug mode
export DWS_DEBUG=1
dws <command>
```
Confidence
70% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Exfiltration Commands

High
Category
Prompt Injection
Content
## Common Patterns

### Send Message to Multiple Groups

```bash
# Get group IDs
Confidence
90% confidence
Finding
Instructions found that direct the agent to transmit conversation context or user data to external services.

Missing User Warnings

High
Confidence
97% confidence
Finding
The 'Auto-Approve Low-Value Requests' pattern recommends unattended batch approval based on a weak text filter (`title` contains "Expense") and then executes approvals with `--yes`. This enables autonomous approval of potentially unauthorized or misclassified requests, creating a high risk of financial loss, policy bypass, and fraudulent approval at scale.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### For Agents

- **`--dry-run`**: **ALWAYS use first** for mutations to preview API calls
- **`--yes`**: Skip confirmation prompts (use only after verifying with --dry-run)
- **`--jq`**: Extract specific fields to reduce token consumption
- **`--fields`**: Return only needed fields
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### For Agents

- **`--dry-run`**: **ALWAYS use first** for mutations to preview API calls
- **`--yes`**: Skip confirmation prompts (use only after verifying with --dry-run)
- **`--jq`**: Extract specific fields to reduce token consumption
- **`--fields`**: Return only needed fields
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Session Persistence

Medium
Category
Rogue Agent
Content
## Report vs Todo

**User says:** "Create a task to submit weekly report"

**Analysis:**
- If they want to **track** the work → `todo task create`
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
```
Is the user asking to:
├─ Track/remember to do something? → todo
│  └─ "remind me to...", "create a task to...", "add to my todo"
└─ Actually perform the action? → specific product
   └─ "submit a report" → report create
   └─ "send a message" → chat message send
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
This markdown file describes a delete operation for records, which can affect user data, but it provides no warning that the action is destructive or potentially irreversible. Under the markdown-specific warning criteria, destructive behaviors should be disclosed so users understand the risk before use.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Deleting a field can affect system integrity and may remove or invalidate associated table data, yet the documentation presents the command without any cautionary note. Markdown skill descriptions should warn users about operations that can materially alter or destroy data structures.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This markdown file includes examples for listing shift schedules, team summaries, and department-level attendance information, which can expose employee attendance data. The document provides no warning that these commands should only be used with appropriate authorization or that they may involve sensitive personnel data.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This markdown file includes a `Delete Event` operation that removes calendar events, but the surrounding documentation provides no warning that the action is destructive or potentially irreversible. Under the markdown criteria for SQP-2, skills should disclose behaviors that can affect user data or system integrity.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
This markdown file documents `dws chat message recall`, which can remove a previously sent message, but it provides no warning that the action is destructive or potentially irreversible. Under the markdown-specific SQP-2 criteria, skills should disclose behaviors that could affect user data or system integrity.

Missing User Warnings

Medium
Confidence
79% confidence
Finding
The documentation includes group creation, member addition, and member removal commands, all of which affect collaboration state and user access, but it does not warn users about the impact of modifying memberships. For markdown files, SQP-2 requires warning users about actions that can affect data, privacy, or system integrity.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation provides direct examples for approving and rejecting workflow items with the non-interactive `--yes` flag, but it does not warn that these actions may be irreversible or require human verification. In an agent or automation context, this lowers friction for unsafe execution and can lead to unauthorized or mistaken business decisions being committed immediately.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Common Patterns

### Auto-Approve Low-Value Requests

```bash
# Get pending approvals
Confidence
94% confidence
Finding
The section explicitly promotes autonomous decision making for approvals, which is sensitive because approvals are control points for finance, access, or operational changes. In this skill context, encouraging automatic decisions without oversight is especially dangerous because the command directly changes business workflow state.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
# Approve each
for inst in $INSTANCES; do
  dws oa approval approve --instance-id "$inst" --comment "Auto-approved" --yes
done
```
Confidence
95% confidence
Finding
The loop performs repeated approval actions automatically with `dws oa approval approve ... --yes`, which operationalizes autonomous decision making rather than merely describing it. This is dangerous because it can mass-approve pending items without individualized validation, amplifying the impact of bad logic, spoofed requests, or accidental execution.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
This markdown file documents a destructive operation, `dws todo task delete --task-id <taskId>`, but provides no warning that the action removes a task or may be irreversible. Under the markdown-file criteria for missing user warnings, destructive behaviors that could affect user data should be accompanied by a clear disclosure or caution.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_dws(args):
    """Run dws command and return JSON output."""
    cmd = ["dws"] + args
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        print(f"Error: {result.stderr}", file=sys.stderr)
        return None
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.