Back to skill

Security audit

Feishu Send Files

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real Feishu file-sending tool, but it can upload local files with broad chat triggers and too little confirmation or path restriction.

Review this before installing in any shared or production OpenClaw environment. Only use it where chat participants are trusted, Feishu recipients are verified, and the process has access only to files that are safe to send. The publisher should restrict sends to an approved directory, require confirmation showing path, size, and recipient, remove contains triggers, enforce file size/type checks, and replace 777 log permissions with owner-only permissions.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
index.js:273
Finding
Arbitrary Local File Disclosure Through Unrestricted Absolute Paths<![CDATA[ ## Vulnerability Details **File Location**: `index.js:273-281`, `index.js:352-356` **Vulnerability Type**: Missing file-access authorization and path restriction **Risk Level**: High ### Vulnerable Code ```javascript // Match absolute paths const absPathMatch = text.match(/(\/[^\s]+)/g) if (absPathMatch) { for (const p of absPathMatch) { if (p.startsWith('/') && !p.startsWith('/open-apis') && !p.startsWith('/api') && fs.existsSync(p)) { return p } } } ``` ```javascript // Attempt to extract a file path directly let filePath = extractFilePath(userInput) if (filePath && fs.existsSync(filePath)) { await sendFile(context, token, filePath, isGroup, chatId, openId) return } ``` ### Technical Analysis The Skill treats any existing absolute path contained in a chat message as an authorized file to transmit. Validation is limited to checking that the path exists and does not begin with `/open-apis` or `/api`. The implementation does not: - Restrict files to the OpenClaw workspace or another approved directory. - Verify that the caller is authorized to access the requested file. - Require confirmation before transmitting sensitive files. - Resolve and validate canonical paths. - Prevent symbolic-link escapes. - Verify that the target is a regular file. - Restrict sensitive file names, directories, or file types. The file is subsequently read using the OpenClaw process's operating-system privileges, uploaded to Feishu, and sent to the current group or private conversation. This creates a confused-deputy condition: a chat participant may use the bot's filesystem permissions to retrieve files that the participant could not access directly. ### Attack Path 1. An attacker gains access to a conversation in which the Skill can be invoked. 2. The attacker submits a request containing a sensitive absolute path, for example: ```text Send file /home/node/.openclaw/openclaw.json ``` 3. `extractFilePath()` finds the path and accept ...[truncated 1265 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict file transmission to explicitly approved root directories, such as a dedicated outbound-files directory. 2. Resolve both the approved root and requested path with `fs.realpathSync()` before validation. 3. Verify that the canonical requested path remains inside the canonical approved root: ```javascript const root = fs.realpathSync(approvedRoot) const requested = fs.realpathSync(inputPath) const relative = path.relative(root, requested) if (relative.startsWith('..') || path.isAbsolute(relative)) { throw new Error('The requested file is outside the approved directory') } ``` 4. Use `fs.lstatSync()` and `fs.statSync()` to reject symbolic links, directories, devices, FIFOs, sockets, and other non-regular files. 5. Apply caller-level authorization. Only explicitly permitted Feishu users or groups should be able to invoke file transmission. 6. Require explicit confirmation that shows the canonical path, recipient, and file size before uploading sensitive or externally supplied paths. 7. Consider maintaining a server-generated file identifier list instead of accepting arbitrary paths from chat text. 8. Deny known-sensitive directories and file patterns as defense in depth, including OpenClaw configuration, credentials, SSH material, and environment files. 9. Add security tests for path traversal, symbolic-link escape, sensitive absolute paths, unauthorized callers, and non-regular files. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:143
Finding
Denial of Service Through Unbounded Synchronous File Loading<![CDATA[ ## Vulnerability Details **File Location**: `index.js:143-150` **Vulnerability Type**: Unbounded memory allocation and blocking filesystem operation **Risk Level**: Medium ### Vulnerable Code ```javascript function uploadFile(token, filePath, fileName) { return new Promise((resolve, reject) => { const fileData = fs.readFileSync(filePath) const boundary = `----feishu-upload-${Date.now()}` const bodyArr = [ Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file_type"\r\n\r\nstream\r\n`), Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file_name"\r\n\r\n${fileName}\r\n`), Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="${fileName}"\r\nContent-Type: application/octet-stream\r\n\r\n`), fileData, Buffer.from(`\r\n--${boundary}--\r\n`) ] const formData = Buffer.concat(bodyArr) ``` ### Technical Analysis `uploadFile()` loads the complete requested file into memory with `fs.readFileSync()`. It then creates additional buffers and combines them with `Buffer.concat()`, causing memory usage to exceed the original file size. No size check is performed before reading the file. Although the documentation mentions a 30 MB Feishu limit, that limit is not enforced by the implementation. The synchronous read also blocks Node.js's event loop until the operation completes. Because the Skill accepts absolute paths and command-line file paths, an attacker or operator can select a very large readable file. Concurrent or repeated requests can amplify resource usage. The absence of a regular-file check also means the function may be invoked on unsuitable filesystem objects. ### Attack Path 1. An attacker identifies a very large file readable by the OpenClaw process or places a large file in an accessible location. 2. The attacker asks the bot to send that file, or an untrusted local caller supplies it through `--file`. 3. `uploadFile()` synchrono ...[truncated 896 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Inspect the path with `lstat()` and `stat()` before opening it. 2. Reject anything that is not a regular file. 3. Enforce a strict server-side maximum size before upload, preferably at or below the Feishu API limit. 4. Use asynchronous, streaming I/O rather than `fs.readFileSync()`. 5. Construct the multipart request as a stream so the complete file and request body are not duplicated in memory. 6. Enforce per-user rate limits and a maximum number of concurrent uploads. 7. Abort stalled requests and destroy the HTTPS request when a timeout occurs. 8. Return a clear validation error before obtaining a token or allocating upload buffers. 9. Add tests using oversized files, concurrent uploads, symbolic links, directories, and non-regular filesystem objects. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
index.js:68
Finding
World-Writable Log Directory and Unsafe Permission Guidance<![CDATA[ ## Vulnerability Details **File Location**: `index.js:68-71`, `SKILL.md:194` **Vulnerability Type**: Excessively permissive filesystem permissions **Risk Level**: Low ### Vulnerable Code ```javascript try { if (!fs.existsSync(logDir)) { fs.mkdirSync(logDir, { recursive: true, mode: 0o777 }) } } catch (err) { ``` The documentation additionally recommends: ```text chmod -R 777 logs ``` ### Technical Analysis The Skill requests mode `0777` when creating its log directory, and its troubleshooting documentation explicitly advises operators to recursively make the directory and its contents world-readable and world-writable. Although the effective mode may be reduced by the process umask, secure behavior must not depend on an external umask. Following the documented command grants every local account permission to read, alter, replace, or delete log files. The logs include operational data such as conversation type, chat identifiers, user identifiers, recipient identifiers, selected file names, and status messages. A writable log directory also creates file-integrity and symbolic-link risks where an attacker has local access and can manipulate directory contents before the privileged process opens a predictable daily log filename. ### Attack Path 1. An operator creates the directory with the requested mode or follows the documented `chmod -R 777 logs` instruction. 2. A lower-privileged local user accesses the world-writable log directory. 3. The user reads identifiers and operational information from existing logs, modifies or deletes audit records, or replaces a predictable log entry with a symbolic link. 4. The Skill later appends to the attacker-controlled file entry. 5. Audit integrity is lost; depending on ownership and target permissions, symbolic-link manipulation may also redirect log output to an unintended file. This attack requires local access to the host and sufficient access to traverse the parent project directories. ### Im ...[truncated 462 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the log directory with owner-only permissions: ```javascript fs.mkdirSync(logDir, { recursive: true, mode: 0o700 }) ``` 2. Create log files with mode `0600`, and verify their ownership and type before appending. 3. Remove the `chmod -R 777 logs` recommendation from `SKILL.md`. 4. Recommend `chmod 700 logs` and `chmod 600 logs/*.log` when correcting permissions. 5. Use `lstat()` to reject symbolic links before opening a log file. 6. Where supported, open logs with flags that prevent following symbolic links and use securely managed file descriptors. 7. Avoid logging recipient or conversation identifiers unless operationally necessary; redact or truncate identifiers where possible. 8. Implement log rotation and retention limits to reduce exposure. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The skill is presented as a simple file-sending utility, but the documentation reveals materially broader capabilities: recursive local file search, reading arbitrary user-specified paths, creating logs/config files, and making outbound API calls. That mismatch weakens informed consent and makes it easier for a user or calling agent to trigger sensitive file discovery and exfiltration behavior without clearly understanding the scope.

Vague Triggers

High
Confidence
97% confidence
Finding
The documented trigger phrases include broad natural-language patterns such as common requests to 'send' or '发一下', which overlap with ordinary conversation. In a chat-integrated skill that can search local files and send them externally, unintended activation materially increases the risk of accidental file disclosure.

Vague Triggers

High
Confidence
98% confidence
Finding
The trigger rule set uses ambiguous `prefix_match` and especially `contains` rules for phrases like '发文件' and '发送文件', making activation possible from incidental text. Given the skill can recursively search the workspace and transmit files, this broad matching meaningfully raises the chance of unintended execution and data exfiltration.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
|------|----------|
| **文件发错地方(发到个人而不是群里)** | 机器人触发时自动识别;命令行调用必须加 `--to "chat:群聊 ID"` |
| 文件名异常 | 使用最终版 index.js |
| 无日志 | 赋权 logs 目录:`chmod -R 777 logs` |
| 机器人无响应 | 重启 OpenClaw,检查文件路径 |
| 发送失败 | 检查飞书权限与 appId/appSecret 配置 |
| token 获取失败 | 检查 appId/appSecret 是否正确 |
Confidence
98% confidence
Finding
Recommending `chmod -R 777 logs` instructs users to make the log directory world-readable and world-writable. If logs contain filenames, recipient identifiers, tokens, errors, or other operational details, this can enable local tampering, unauthorized reading, or destruction of forensic evidence by other users/processes on the system.

Vague Triggers

High
Confidence
96% confidence
Finding
The prefix triggers like '帮我发', '发一下', and '把文件' are so generic that the skill can activate during ordinary conversation rather than an explicit file-send request. In a messaging/file-transfer skill, accidental activation is dangerous because it may cause unintended file delivery, recipient auto-selection, or leakage of sensitive local files through natural-language ambiguity.

Vague Triggers

High
Confidence
96% confidence
Finding
Contains-match triggers for common phrases like '发文件' and '发送文件' can fire when those words appear anywhere in a message, including discussion about sending files rather than a request to do so. Because this skill performs outbound file transmission, unintended activation can directly lead to privacy breaches, misdelivery, or unauthorized actions with minimal user awareness.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The README explicitly promotes sending arbitrary local files to Feishu, but it does not clearly warn users that file contents will leave the local machine and be transmitted to an external service. In an agent/automation context, this increases the risk of unintended exfiltration of sensitive documents, keys, or internal data if users or upstream prompts provide broad paths or ambiguous search terms.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The documentation says the recipient parameter is required, but also states the tool will default to sending to a personal recipient if it is omitted. This inconsistency can cause accidental delivery of sensitive files to the wrong destination, especially in CLI or automated contexts where operators assume omission will fail safely.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill silently creates a recipient configuration file in the user's home workspace based on global configuration, without explicit consent. Unexpected persistence of messaging targets can alter future behavior, leak recipient metadata to disk, and make later file transmission happen to an unintended default target.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
In robot mode, the skill extracts file paths or searches the workspace from free-form user input and then uploads matching local files to Feishu. Because it does not clearly warn that local file contents will be transmitted externally or require an explicit confirmation step, users can unintentionally exfiltrate sensitive local data, especially in chat-driven workflows where intent may be ambiguous.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The batch-selection flow supports sending multiple matched files or all matches with a simple reply, but it provides no explicit safety warning about transmitting those files to an external service. This amplifies the risk of accidental bulk exfiltration from the workspace, particularly because matching is based on broad search results and the user may not inspect every selected file carefully.

Natural-Language Policy Violations

Medium
Confidence
83% confidence
Finding
The natural-language description is written as a Chinese-only interaction model and states support for commands and natural language without indicating that users may choose another language. Under the policy, language constraints should be optional or explicitly justified when the skill enforces a locale.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The note text is written only in Chinese ("示例配置 - 请替换为你的用户 Open ID"), which imposes a specific language in a user-facing configuration comment. The file does not provide an alternative language, opt-in, or any indication that the skill is intentionally region-specific.

Context-Inappropriate Capability

Low
Confidence
76% confidence
Finding
The stated purpose is a Feishu bulk file sending skill, but this function additionally reads from and auto-writes recipient configuration under the user's home directory. Persisting local recipient defaults is a convenience feature rather than an obvious requirement of file delivery itself, so it adds capability beyond the manifest's narrow stated purpose.

Context-Inappropriate Capability

Low
Confidence
84% confidence
Finding
The manifest describes a file sending skill, but the code also creates a logs directory and continuously appends operational data to disk. Local logging is not an obvious user-facing requirement of bulk file sending, especially when the description emphasizes simplicity and zero dependency rather than filesystem side effects.

Vague Triggers

Low
Confidence
82% confidence
Finding
This manifest only provides a brief description of the skill as a Feishu bulk file sending skill, but does not specify how or when it should be invoked. For manifest files, missing specificity around trigger scope or constraints can lead to unintended or overly broad activation behavior.

Static analysis

No suspicious patterns detected.