Back to skill

Security audit

单向历

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but it needs review because a crafted configuration value could make its send script run arbitrary local shell commands.

Review before installing. Only use this skill if you trust and protect its config.json, verify the Feishu recipient ID, and understand it will contact Feishu and the configured image host. The send script should be fixed to avoid shell-string execution and to strictly validate userId and baseUrl before relying on scheduled sends.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/send.js:49
Finding
Shell Command Injection Through Untrusted Configuration Values## Vulnerability Details **File Location**: `scripts/send.js`, lines 49–50 **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```js function sendImage(userId, imageUrl) { const cmd = `openclaw message send --channel=feishu --target=${userId} --media="${imageUrl}"`; execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }); } ``` The values passed into this function originate from `config.json`. The relevant configuration loading and validation occur in `scripts/send.js`: ```js const userId = config.feishu?.userId; const baseUrl = config.settings?.baseUrl || 'https://img.owspace.com/Public/uploads/Download'; validateUserId(userId); const { label, url } = getTodayImageUrl(baseUrl); ``` The validation at lines 29–34 only requires the user ID to begin with `ou_`: ```js function validateUserId(id) { if (!id || !id.startsWith('ou_')) { console.error('❌ 飞书用户 ID 无效,请重新配置:node scripts/setup.js'); process.exit(1); } } ``` ### Technical Analysis `execSync()` receives a single command string and executes it through a shell. Both `userId` and `imageUrl` are interpolated into that string without shell-safe argument handling. The `userId` is unquoted and is only subject to a prefix check. A value beginning with `ou_` can therefore still contain shell control operators such as `;`, `&&`, `|`, redirects, or command substitutions. Although `imageUrl` appears between double quotes, this is not sufficient shell escaping. Command substitution forms such as `$(...)` and backticks are still evaluated inside double quotes. The configurable `baseUrl` is not parsed or validated before it becomes part of `imageUrl`. Consequently, anyone able to influence `config.json` or provide a crafted ID during interactive setup can cause arbitrary shell commands to execute when the calendar script runs. ### Attack Path 1. An attacker gains the ability to modify `config.json`, influences configuration deployment, or convinc ...[truncated 1493 chars]
Remediation
## Remediation Suggestions 1. **Remove shell-based command construction.** Use `execFileSync()` or `spawnSync()` with a fixed executable and separate argument array: ```js const { execFileSync } = require('child_process'); function sendImage(userId, imageUrl) { execFileSync( 'openclaw', [ 'message', 'send', '--channel=feishu', `--target=${userId}`, `--media=${imageUrl}`, ], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], shell: false, } ); } ``` This prevents configuration values from being interpreted as shell syntax. 2. **Apply strict allowlist validation to the Feishu user ID.** Replace the prefix-only check with a complete format check, based on the exact format Feishu guarantees. For example: ```js function validateUserId(id) { if (typeof id !== 'string' || !/^ou_[A-Za-z0-9]+$/.test(id)) { throw new Error('Invalid Feishu user ID'); } } ``` 3. **Validate the configured base URL.** Parse it with the standard `URL` class, require HTTPS, reject embedded credentials, and preferably restrict the hostname to the intended provider: ```js function validateBaseUrl(value) { const parsed = new URL(value); if ( parsed.protocol !== 'https:' || parsed.hostname !== 'img.owspace.com' || parsed.username || parsed.password ) { throw new Error('Invalid image base URL'); } return parsed.toString().replace(/\/$/, ''); } ``` 4. **Validate the final media URL** before passing it to OpenClaw, including its scheme, hostname, and expected path structure. 5. **Protect configuration integrity.** Create `config.json` with restrictive permissions appropriate to the platform and ensure only the owning user can modify it. 6. **Add regression tests** covering semicolons, pipes, redirects, whitespace, quotes, backticks, `$()` substitutions, newl ...[truncated 77 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Ae1

High
Category
analysis-evasion
Content
node scripts/send.js
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation describes a workflow that sends a message to Feishu and retrieves an external image from a third-party server, but it does not clearly warn users that their configured Feishu user ID and request metadata will be transmitted over the network. In a skill context, this omission can lead users to disclose identifiers or trigger outbound requests without understanding the privacy and data-flow implications.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The script builds a shell command with interpolated values from configuration (`userId`) and from `baseUrl` via the derived `imageUrl`, then executes it with `execSync`. Although `userId` is prefix-checked, neither value is safely escaped for shell execution, so a crafted config can inject additional shell syntax and execute arbitrary commands on the host running the skill.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
User-facing strings throughout the setup flow are written only in Chinese, including the title, instructions, prompts, and error messages. This imposes a specific language on all users without opt-in, which matches the language/locale policy violation criteria.

Missing User Warnings

Low
Confidence
86% confidence
Finding
The markdown explains that the skill supports scheduled daily sending and later instructs users to configure a Feishu user ID, but it does not include any warning that the skill will automatically send outbound messages on the user's behalf once scheduled. For a markdown file, this is a missing user warning because the described behavior affects messaging activity and uses recipient-identifying data.

Missing User Warnings

Low
Confidence
93% confidence
Finding
The README instructs users to inspect live logs to recover a Feishu user ID without warning that logs may also contain identifiable messaging metadata. This can encourage unsafe handling of operational logs and unnecessary exposure of user identifiers, especially on shared systems or when logs are retained centrally.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The configuration example fixes the timezone to Asia/Shanghai, which is a locale-specific default. The file does not indicate that users may change it or explain why this locale is required, which can violate language/locale policy expectations when no opt-in or justification is provided.

Natural-Language Policy Violations

Low
Confidence
91% confidence
Finding
The config sets the timezone to "Asia/Shanghai", which imposes a specific locale-related default in natural language/configuration policy terms. There is no indication here that the user can choose a different locale or that the setting is justified as region-specific behavior.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/send.js:55

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/setup.js:60