Back to skill

Security audit

Dingtalk Docs 0.3.1

Security checks for vulnerabilities and agentic risk

Overview

This DingTalk document skill appears purpose-related rather than malicious, but it needs review because it can read and overwrite cloud documents, create broader resource types than its stated trigger scope, relies on an unpinned global helper, and can overwrite local export files.

Install only if you are comfortable granting this skill access to your DingTalk document service URL and letting it read, create, and modify documents. Review requested actions carefully, especially overwrite writes, non-document node creation such as tables or PPTs, and export destinations. Prefer a pinned, local mcporter installation and avoid using sensitive existing workspace files as export targets.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
package.json:31
Finding
Unpinned Globally Installed Dependency Creates Supply-Chain Risk<![CDATA[ ## Vulnerability Details **File Location**: `package.json:31-34`; related installation instructions at `README.md:21-25` **Vulnerability Type**: Unpinned third-party dependency installed globally **Risk Level**: Medium ### Vulnerable Code `package.json:31-34`: ```json "peerDependencies": { "mcporter": ">=0.7.0" }, ``` `README.md:21-25`: ```markdown ### 2. Install Dependencies ```bash npm install -g mcporter ``` ``` ### Technical Analysis The dependency declaration accepts every `mcporter` release from version 0.7.0 onward, while the documented installation command installs the registry's current default release globally. The project provides no exact version pin, lockfile, package integrity value, or documented publisher verification procedure. `mcporter` is security-sensitive in this project because it receives the token-bearing DingTalk MCP endpoint and processes document identifiers and document contents. Installing it globally also causes its executable to be available system-wide under the user's account. This does not prove that the current `mcporter` package is malicious. The vulnerability is the absence of controls ensuring that users install the same reviewed artifact over time. A compromised publisher account, malicious future release, or registry-level package substitution could therefore introduce code that was not covered by this audit. ### Attack Path 1. An attacker compromises the package publisher, publishing process, or package registry entry for a future `mcporter` release. 2. The malicious release remains compatible with the permissive `>=0.7.0` declaration. 3. A user follows the documented `npm install -g mcporter` command, which retrieves the current registry-selected release without an exact version or integrity check. 4. The malicious package executes installation-time code, or its executable runs when the Skill invokes `mcporter`. 5. The compromised executable receives DingTalk MCP requests and may access the confi ...[truncated 983 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `mcporter` to a reviewed exact version rather than using a lower-bound range: ```json "peerDependencies": { "mcporter": "0.7.0" } ``` 2. Change the installation instructions to specify the same reviewed version: ```bash npm install --save-dev --save-exact mcporter@0.7.0 ``` 3. Prefer a project-local dependency over a global installation, and invoke it through a package script or a locked package manager workflow. 4. Commit a lockfile containing resolved versions and integrity hashes. 5. Document the expected npm registry, package publisher, and package provenance. Where supported, verify package signatures or provenance attestations before installation. 6. Review dependency updates before changing the pin, including package ownership, install scripts, transitive dependencies, and release differences. 7. Run the dependency with the minimum necessary operating-system and DingTalk permissions, and avoid exposing unrelated environment variables or files to it. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export_docs.py:59
Finding
Document Export Silently Overwrites Existing Workspace Files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/export_docs.py:59-63`; invocation at `scripts/export_docs.py:104-107` **Vulnerability Type**: Unprotected destructive file overwrite **Risk Level**: Medium ### Vulnerable Code `scripts/export_docs.py:59-63`: ```python def save_content(content: str, path: Path) -> bool: """保存内容到文件""" try: with open(path, 'w', encoding='utf-8') as f: f.write(content) return True ``` `scripts/export_docs.py:104-107`: ```python # 保存文件 print("\n步骤 2: 保存文件...") if not save_content(content, safe_output): sys.exit(1) ``` ### Technical Analysis The export destination is opened in `w` mode without checking whether the file already exists and without requiring explicit overwrite authorization. Python truncates an existing file immediately when it is opened in this mode. The workspace-containment check in `resolve_safe_path` limits where the operation can write, but it does not protect existing files inside that workspace. Consequently, any regular workspace file selected as the output destination can be replaced by retrieved DingTalk document content. There is also no backup, atomic temporary-file workflow, or recovery mechanism. If writing fails after truncation, the original file may already have been destroyed and the replacement may be incomplete. ### Attack Path 1. The user, an automated agent, or crafted task input supplies an output path that names an existing file inside `OPENCLAW_WORKSPACE`. 2. `resolve_safe_path` accepts the destination because it is contained within the allowed workspace. 3. The script retrieves content from an authorized DingTalk document. 4. `save_content` executes `open(path, 'w', encoding='utf-8')`. 5. The operating system truncates the existing destination file before the replacement content is fully written. 6. The original local content is irreversibly replaced unless an independent backup or version-control copy exists. No privilege escalati ...[truncated 754 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject existing destinations by default using exclusive creation: ```python def save_content(content: str, path: Path, overwrite: bool = False) -> bool: if path.exists() and not overwrite: print(f"Destination already exists: {path}") return False mode = 'w' if overwrite else 'x' try: with open(path, mode, encoding='utf-8') as file: file.write(content) return True except Exception as error: print(f"Failed to save file: {error}") return False ``` 2. Add an explicit `--force` or `--overwrite` option. Overwrite only when the user knowingly supplies that option. 3. For interactive operation, display the resolved destination and request confirmation before replacing an existing file. 4. Write retrieved content to a temporary file in the same directory, flush and synchronize it, and then atomically replace the destination only after the complete write succeeds. 5. Optionally create a backup before an authorized overwrite, particularly for non-generated files. 6. Add tests covering: - Rejection of an existing destination by default. - Successful creation of a new file. - Explicit overwrite behavior. - Preservation of the original destination when retrieval or writing fails. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (23)

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
声明描述的是一个较完整的“钉钉云文档管理”技能,覆盖创建、搜索、读写内容和文件夹管理等云端操作;但实际代码只实现了非常具体的单一功能:根据文档 URL 获取内容并导出到本地文件。虽然“读取文档内容”属于声明的一部分,但实际主要行为还包括本地文件写入,这属于未明确声明的能力;同时,声明中的大部分核心管理能力在该代码中并未体现。两者的主要用途存在实质性偏差:声明是通用云文档管理,代码是本地导出脚本,因此应判定为描述与行为不匹配。

Credential Access

High
Category
Privilege Escalation
Content
| 用例 | 说明 | 结果 |
|------|------|------|
| 目录遍历攻击 | `../etc/passwd` → 应拒绝 | ✅ |
| 绝对路径越界 | `/etc/passwd` → 应拒绝 | ✅ |
| 合法相对路径 | 工作目录内文件 → 应通过 | ✅ |
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
| 用例 | 说明 | 结果 |
|------|------|------|
| 目录遍历攻击 | `../etc/passwd` → 应拒绝 | ✅ |
| 绝对路径越界 | `/etc/passwd` → 应拒绝 | ✅ |
| 合法相对路径 | 工作目录内文件 → 应通过 | ✅ |
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
| 用例 | 说明 | 结果 |
|------|------|------|
| 目录遍历攻击 | `../etc/passwd` → 应拒绝 | ✅ |
| 绝对路径越界 | `/etc/passwd` → 应拒绝 | ✅ |
| 合法相对路径 | 工作目录内文件 → 应通过 | ✅ |
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
| 用例 | 说明 | 结果 |
|------|------|------|
| 目录遍历攻击 | `../etc/passwd` → 应拒绝 | ✅ |
| 绝对路径越界 | `/etc/passwd` → 应拒绝 | ✅ |
| 合法相对路径 | 工作目录内文件 → 应通过 | ✅ |
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
This markdown file documents a content-writing operation, including overwrite mode, which can directly alter user data. Although the README explains how to call the method, it does not warn users about the risk of overwriting existing document content or recommend verifying the target before execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest says the skill should not trigger for 多维表 operations, yet the body explicitly instructs handling 多维表 creation via accessType="7". This contradiction can cause the agent to activate in out-of-scope contexts and perform unintended actions on different object types than users or reviewers expect.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger description includes broad natural-language phrases such as references to cloud docs and related everyday wording, which can cause the skill to activate when the user intent is ambiguous. Overbroad activation is dangerous for a write-capable skill because it may steer conversations into document operations the user did not intend, including creation or content changes.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
Inline instructions first say not to default to documents when users mention '表格' because they may want an online spreadsheet or 多维表, while the manifest says the skill should not trigger for multidimensional-table operations. Contradictory routing guidance increases the chance of misclassification and unintended creation or modification of the wrong resource type.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documented methods extend beyond document and folder management into spreadsheets, PPTs, mind maps, and multidimensional tables, which exceeds the declared manifest scope. Scope expansion without matching declaration weakens reviewer and user understanding of what the skill may do, increasing the risk of unintended destructive or privacy-impacting actions in adjacent product surfaces.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The intent examples use very general phrases like '查一下', '打开文档', and '帮我建个文档' without stronger scope constraints or identity checks for the target resource. In a skill that can search, read, create, and overwrite content, vague matching raises the risk of operating on the wrong document or invoking sensitive actions from casual language.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The skill description uses broad keyword-trigger language such as references to '云文档、在线文档、钉钉文档、钉文档等关键词的场景', which can cause activation based on generic mentions rather than clear user intent to perform document actions. In a skill that can read, write, create, and organize cloud documents, over-triggering increases the chance of unintended access or modification of user content.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The reference file exposes capabilities beyond the skill’s declared scope by documenting creation of tables, PPTs, whiteboards, mind maps, videos, images, PDFs, and other files. This creates scope drift: an orchestrator or downstream agent may invoke broader write operations than users or reviewers expect, weakening least-privilege assumptions and enabling unintended modification or creation of non-document artifacts in the user’s DingTalk workspace.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The documented ability to create multidimensional tables and other non-document resources is not justified by the stated skill purpose, which says it should not trigger for 多维表 scenarios. That mismatch is dangerous because it can cause an agent to perform actions in prohibited or unexpected domains, increasing the chance of unauthorized content creation, policy bypass, or user confusion about what the skill is allowed to do.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This Python file contains natural-language instructions and runtime messages exclusively in Chinese, which effectively forces a specific language for usage and error handling. The policy allows locale constraints only when users are given a choice or the constraint is clearly justified, neither of which is present here.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The script retrieves document content from DingTalk and writes it to a local filesystem path, creating a data exfiltration path from a managed cloud document environment to local storage. In the context of a skill described as managing documents within DingTalk, this broadens data movement and can expose sensitive content to less-controlled locations, even though the path handling includes some safety checks.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This file contains natural-language instructions, usage examples, and runtime messages only in Chinese. Under the policy rule, forcing a specific language without opt-in is a locale/language policy violation unless the restriction is explicitly justified, which is not present here.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args:
        command.extend(['--args', json.dumps(args, ensure_ascii=False)])
    try:
        result = subprocess.run(
            command,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
This Python file contains a top-level natural-language docstring written only in Chinese ("安全功能测试用例…") with no indication that language choice is optional or justified by a region-specific requirement. Under the policy for natural-language violations, forcing a specific language without opt-in can be a locale-policy issue.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
This markdown file contains user-facing natural language almost entirely in Chinese, including headings and descriptions of changes, with no indication that language selection is optional. Under the language/locale policy rule, forcing a specific language without user opt-in is a policy concern unless clearly justified as region-specific.

Natural-Language Policy Violations

Low
Confidence
76% confidence
Finding
The README content is entirely in Chinese, which may impose a language requirement on users without opt-in or an explicit statement that the skill is intended for a Chinese-language audience. Under the language/locale policy rule, forcing a specific language without user choice can be a policy concern.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
This markdown file uses Chinese throughout the document, but does not state that the skill or its documentation is intended specifically for Chinese-speaking users or a China-specific deployment. Under the natural-language policy rule, forcing a specific language without user opt-in or documented justification can be a locale-policy violation.

Static analysis

No suspicious patterns detected.