Back to skill

Security audit

dingtalk-docs-skill

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its DingTalk document purpose, but its setup can persist a personal API-key URL in agent configuration and allows bypassing the official-domain check.

Review before installing. Use only an official HTTPS DingTalk MCP URL, prefer project-local configuration, do not approve non-DingTalk endpoints, and check that any MCP config file containing the URL is not committed or shared. Treat pasted or logged MCP URLs as credentials that may need rotation.

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

Error
Location
SKILL.md:60
Finding

Bypassable MCP Endpoint Domain Allowlist

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:60
Vulnerability Type: Confirmation-based bypass of a security boundary
Risk Level: High

Complete Vulnerable Snippet — translated faithfully into English from the source:

text
① URL domain allowlist: Only accept official DingTalk domains—
aihub.dingtalk.com, alidocs.dingtalk.com, and other *.dingtalk.com
subdomains. If the URL domain is not in the allowlist, stop registration
and tell the user that the URL may be incorrect or risky. Continue only
after the user confirms.

Technical Analysis

The instructions describe the domain check as an allowlist intended to prevent MCP traffic, including a personal API key, from being sent to an incorrect or malicious endpoint. However, the same instruction permits registration to continue after user confirmation.

This converts a mandatory trust boundary into a warning prompt. A user can be socially engineered into approving an attacker-controlled endpoint, so the check does not reliably enforce the stated restriction. The instructions also do not specify strict URL parsing, HTTPS enforcement, rejection of embedded credentials, or hostname canonicalization. An implementation using textual suffix matching could consequently be exposed to deceptive hostnames or URL parsing ambiguity.

Attack Path

  1. An attacker supplies or recommends a StreamableHttp URL hosted outside an official DingTalk domain.
  2. The Skill detects that the hostname is not allowlisted and displays a warning.
  3. The attacker persuades the user to confirm registration despite the warning.
  4. The Skill registers the untrusted endpoint under the trusted service name dingtalk-doc.
  5. Subsequent MCP calls transmit request metadata and potentially sensitive document operations to that endpoint.
  6. If the URL contains authentication material, that material is also disclosed to the endpoint or retained in its logs.
  7. Later uploads or d ...[truncated 890 chars]
Remediation
View remediation

Remediation Suggestions

  1. Make the allowlist mandatory. Never permit user confirmation to override a failed endpoint validation.
  2. Parse the URL with a standards-compliant URL parser and validate the normalized hostname, rather than searching the raw URL string.
  3. Require HTTPS and reject URLs containing unexpected schemes, fragments, user-information fields, or malformed ports.
  4. Accept only exact approved hosts or normalized hostnames ending in .dingtalk.com, while separately allowing the apex domain if required.
  5. Reject deceptive names such as dingtalk.com.attacker.example, trailing-dot ambiguities, encoded hostnames, and invalid internationalized domain names.
  6. If an organization must use a nonstandard endpoint, require a separate advanced configuration process with explicit administrator-controlled policy rather than a conversational warning bypass.
  7. Display only a redacted endpoint during confirmation so query parameters containing credentials are not repeated.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:68
Finding

Secret-Bearing MCP URL Exposed Through Command Arguments and Repository-Local Configuration

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:68, 81-98, 113, 148 and README.md:59, 181
Vulnerability Type: Insecure credential handling and plaintext secret storage
Risk Level: Medium

Complete Vulnerable Snippets:

bash
claude mcp add --transport http --scope local dingtalk-doc "<user-provided URL>"
text
Cursor project configuration: .cursor/mcp.json
VS Code Copilot project configuration: .vscode/mcp.json
Gemini CLI global configuration: ~/.gemini/settings.json
OpenAI Codex global configuration: ~/.codex/config.json
json
{
  "mcpServers": {
    "dingtalk-doc": {
      "type": "http",
      "url": "<user-provided URL>"
    }
  }
}

The Skill separately acknowledges that the URL contains a personal API key:

text
The MCP service URL contains a personal API key.

Technical Analysis

The bootstrap procedure interpolates the complete API-key-bearing MCP URL into a command-line argument and stores it as plaintext in MCP configuration files.

Command-line secrets can be exposed through shell history, terminal logs, command auditing, process inspection, debugging output, or copied transcripts. Project-level files such as .cursor/mcp.json and .vscode/mcp.json are located inside a workspace and may be committed to version control unless they are explicitly ignored.

The Skill states that the credential must not be committed, but the audited package contains no .gitignore file and does not require checking whether a target configuration file is already tracked before writing the secret. Its .gitignore assurance specifically concerns references/dingtalk.config, which stores a knowledge-base URL rather than the MCP API key. Therefore, the stated control does not establish protection for project-level MCP configuration.

The README also shows --scope user at lines 59 and 181, while the operative Skill prefers --scope local. This ...[truncated 1811 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer the MCP client's protected credential facility, operating-system keychain, environment-variable reference, or another secret store instead of embedding the API key in a URL stored as plaintext.
  2. Avoid placing the expanded secret in command-line arguments. Use a protected standard-input mechanism or client API when supported.
  3. Never display the full command after substituting the user's URL. Show a redacted preview that preserves only the scheme and hostname.
  4. Before writing project-level configuration:
    • Check whether the target path is tracked by version control.
    • Refuse to write a secret into an already tracked file.
    • Add the exact path to the repository's .gitignore.
    • Verify that the ignore rule is effective.
  5. Set restrictive file permissions, such as owner-only access, where the platform supports them.
  6. Prefer project-local scope over user-global scope and make the README consistent with the operative --scope local guidance.
  7. Warn the user that previously displayed, logged, or committed URLs must be treated as compromised.
  8. Provide explicit credential-rotation instructions for accidental command-history, transcript, or repository exposure.
  9. Add automated tests verifying that secret-bearing values are redacted from responses and that project configuration cannot be written into tracked files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

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

md
| Cursor | `.cursor/mcp.json` | `~/.cursor/mcp.json`(写前确认) | `mcpServers` |
   | VS Code Copilot | `.vscode/mcp.json` | `~/Library/Application Support/Code/User/mcp.json`(Mac)<br>`%APPDATA%\Code\User\mcp.json`(Win)(写前确认) | `servers` |
   | Roo Code | `.roo/mcp.json` | —(无全局需求) | `mcpServers` |
   | Gemini CLI | —(无项目级) | `~/.gemini/settings.json`(仅全局,写前确认) | `mcpServers` |
   | OpenAI Codex | —(无项目级) | `~/.codex/config.json`(仅全局,写前确认) | `mcpServers` |

   向目标文件追加(若文件已有 `mcpServers`/`servers`,只添加新条目,不覆盖原有内容):

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

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

md
| VS Code Copilot | `.vscode/mcp.json` | `~/Library/Application Support/Code/User/mcp.json`(Mac)<br>`%APPDATA%\Code\User\mcp.json`(Win)(写前确认) | `servers` |
   | Roo Code | `.roo/mcp.json` | —(无全局需求) | `mcpServers` |
   | Gemini CLI | —(无项目级) | `~/.gemini/settings.json`(仅全局,写前确认) | `mcpServers` |
   | OpenAI Codex | —(无项目级) | `~/.codex/config.json`(仅全局,写前确认) | `mcpServers` |

   向目标文件追加(若文件已有 `mcpServers`/`servers`,只添加新条目,不覆盖原有内容):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

One eval expects overwrite-mode document updates without requiring a confirmation or warning, which normalizes destructive behavior for an existing cloud document. If an agent follows this pattern on ambiguous or misidentified targets, it could irreversibly replace user content or update the wrong document with limited opportunity for recovery.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The file title and all user-facing documentation are presented entirely in Chinese, with no indication that other languages are supported or that the user can choose a preferred language. Under the language/locale policy, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is documented and justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
83% confidence
Finding

The document explicitly presents only English and Chinese navigation/options, which can be interpreted as a language constraint in the skill's user-facing instructions. Because there is no statement that users may interact in other languages or that the bilingual presentation is merely for documentation convenience, this may conflict with a policy against forcing a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This manifest-like JSON names the skill but provides no narrowing activation conditions, excluded contexts, or specific trigger boundaries. The eval set shows the skill handling very general requests like '帮我更新钉钉上的…' and '把本地文件…推送到钉钉知识库', which could overlap with ordinary user phrasing unless constrained elsewhere.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.