[危险执行模块导致插件安装被拦截] - Plugin Installation Blocked: 'dangerous-exec' Critical Security Finding
合法生成子进程的功能插件(如 apple-pim-cli、parcel-cli)因存在严重安全风险,在安装时被硬性拦截,目前没有提供细粒度的选择机制。
🔍 症状
使用关键安全发现进行安装失败
当尝试安装使用 child_process 来生成本地 CLI 工具的插件时,OpenClaw 安全扫描器会阻止安装并发出关键级别的安全发现。
CLI 执行示例:
$ npx openclaw plugin install apple-pim-cli
Installing plugin 'apple-pim-cli'...
[========================================] 100%
Running security scan...
✗ SECURITY FINDING [CRITICAL]
Rule: dangerous-exec
File: node_modules/apple-pim-cli/dist/index.js
Details: Detected child_process.spawn() call
Plugin installation ABORTED.
Run with --dangerously-force-unsafe-install to bypass.
$ echo $?
1替代输出(详细模式):
$ npx openclaw plugin install apple-pim-cli --verbose
[DEBUG] Fetching plugin manifest from registry...
[DEBUG] Manifest retrieved: apple-pim-cli v2.1.0
[DEBUG] Running security scanner on 847 files...
[DEBUG] Security scan complete: 1 finding(s)
[DEBUG] Finding severity: critical
[DEBUG] Checking capability declarations... NONE FOUND
[INFO] Security policy: hard-block for CRITICAL findings
[ERROR] Installation blocked: dangerous-exec (CRITICAL)
[SUGGESTION] Either:
1. Use --dangerously-force-unsafe-install (not persistent)
2. File a capability declaration request with the plugin author受影响插件的清单特征
表现出此问题的插件通常包含以下一种或多种模式:
"keywords": ["child-process", "cli-wrapper", "native-binary"]在package.json中- 直接导入
child_process模块(spawn、exec、execFile) - 依赖本地 CLI 工具(parcel、esbuild、swipl 等)
- 清单缺少
openclaw或capabilities配置部分
次要症状:令人警觉的术语
使用 –dangerously-force-unsafe-install 标志会产生警告消息,可能会对合法用例中的用户造成恐慌:
$ npx openclaw plugin install apple-pim-cli --dangerously-force-unsafe-install
⚠️ WARNING: You are forcing an install that has critical security findings.
⚠️ This is NOT RECOMMENDED for untrusted plugins.
⚠️ This flag does not persist across updates.
Installing plugin 'apple-pim-cli'...
[========================================] 100%
Installation complete.🧠 根因分析
架构概述
OpenClaw 插件安装管道包含在 src/security/skill-scanner.ts 中实现的安全扫描阶段。该扫描器对插件代码执行静态分析,以检测潜在的危险操作。
故障序列
- 插件注册表查找: OpenClaw 从注册表检索插件清单
- 存档提取: 插件包被下载并提取到临时目录
- 安全扫描启动:
SkillScanner类实例化并开始文件遍历 - 静态分析: 每个 JavaScript/TypeScript 文件都被扫描以查找危险模式
- 模式匹配 - dangerous-exec: 扫描器检测到
require('child_process')或import('child_process') - 严重性分配: 该发现被分配
CRITICAL严重性(硬编码) - 策略执行: 安装策略指定
blockOnCritical: true - 安装中止: 管道在不提取插件的情况下终止
代码路径分析
扫描器检测逻辑(src/security/skill-scanner.ts):
// Pattern: child_process module import
const DANGEROUS_EXEC_PATTERN = /require\s*\(\s*['"]child_process['"]\s*\)|import\s+.*\s+from\s+['"]child_process['"]/;
function scanFile(filePath: string): SecurityFinding | null {
const content = readFileSync(filePath, 'utf-8');
if (DANGEROUS_EXEC_PATTERN.test(content)) {
return {
rule: 'dangerous-exec',
severity: 'critical', // Hardcoded - no capability override check
file: filePath,
message: 'Detected child_process module usage'
};
}
return null;
}关键缺陷: 扫描器在分配严重性之前不检查清单级别的能力声明。能力检查逻辑(checkCapabilities())存在,但在严重性确定阶段从未被调用。
配置不足
当前安全策略配置缺乏粒度:
// src/security/policy.ts
export const DEFAULT_POLICY: SecurityPolicy = {
blockOnCritical: true, // Hard block - no exceptions
blockOnHigh: true,
warnOnMedium: true,
allowOnLow: true,
// MISSING: Capability-aware severity overrides
// Desired: capabilityOverrides: { 'dangerous-exec': { when: { executesCode: true } => 'warn' } }
};清单架构缺失
插件清单架构(src/manifest/schema.ts)不包含 capabilities 字段,这意味着插件无法声明其对子进程的合法使用:
// Current manifest schema (partial)
export interface PluginManifest {
id: string;
name: string;
version: string;
description?: string;
// MISSING: Capabilities declaration
// capabilities?: {
// executesCode?: boolean;
// reason?: string;
// };
}🛠️ 逐步修复
针对插件作者:添加能力声明
如果您维护的插件合法使用 child_process,请在清单中添加能力声明。
步骤 1:确定正确的清单位置
能力声明可以添加到以下任一位置:
- 选项 A: 包根目录中的
openclaw.config.json或openclaw.config.js(首选) - 选项 B:
package.json中的openclaw字段
步骤 2:添加能力声明
之前(package.json):
{
"name": "apple-pim-cli",
"version": "2.1.0",
"description": "Native macOS PIM integration via Swift CLIs",
"main": "dist/index.js"
}之后(package.json):
{
"name": "apple-pim-cli",
"version": "2.1.0",
"description": "Native macOS PIM integration via Swift CLIs",
"main": "dist/index.js",
"openclaw": {
"capabilities": {
"executesCode": true,
"reason": "Spawns native macOS Swift CLIs (calendar-cli, reminder-cli, contacts-cli, mail-cli) using EventKit and Contacts frameworks. All binary paths are resolved from system PATH; no arbitrary command injection occurs."
}
}
}替代方案:单独的 openclaw.config.json
{
"capabilities": {
"executesCode": true,
"reason": "Spawns parcel CLI for package tracking. Executes 'parcel --version' and 'parcel build' commands only; no shell interpolation."
}
}步骤 3:验证清单是否有效
$ npx openclaw manifest validate
Validating manifest for 'apple-pim-cli'...
✓ Schema validation passed
✓ Capability declaration detected:
- executesCode: true
- reason: "Spawns native macOS Swift CLIs..."
✓ Manifest is ready for publication
$ echo $?
0步骤 4:发布更新的插件
$ npm version patch
$ npm publish
npm notice
+ apple-pim-cli@2.1.1针对插件作者:源代码验证(预扫描)
确保您的代码遵循安全模式以避免触发其他安全规则:
步骤 1:审查 child_process 使用情况
$ npx openclaw audit --plugin ./path/to/plugin
Scanning plugin source...
[========================================] 100%
Audit Results:
✓ No shell injection vectors detected
✓ No eval() usage detected
✓ No dynamic command construction detected
✓ child_process usage: execFile (spawn) - safe mode
Recommendation: Your code uses execFile with literal arguments.
This pattern is secure and suitable for capability declaration.步骤 2:尽可能使用 execFile 而不是 exec
避免使用(shell 注入风险):
const { exec } = require('child_process');
// DANGEROUS: Vulnerable to shell injection
exec(`parcel build ${userInput}`, callback);推荐使用(受控执行):
const { execFile } = require('child_process');
// SAFE: Arguments are passed directly, not through shell
execFile('parcel', ['build', '--target', 'node'], callback);针对最终用户:知情同意安装**
步骤 1:在安装前检查插件能力声明
$ npx openclaw plugin info apple-pim-cli
Plugin: apple-pim-cli v2.1.0
Author: apple-pim-team
Registry: openclaw-registry
Capabilities:
⚡ executesCode: true
ℹ️ Reason: Spawns native macOS Swift CLIs using EventKit and
Contacts frameworks.
Security: This plugin requires elevated trust. It will execute
local CLI binaries on your system.
Trust Level: Capability-declared (informed consent required)步骤 2:同意后安装
$ npx openclaw plugin install apple-pim-cli --consent
Installing plugin 'apple-pim-cli'...
Running security scan...
ℹ️ SECURITY NOTICE (Capability Declared)
This plugin declares the following legitimate capability:
- executesCode: true
Reason: Spawns native macOS Swift CLIs using EventKit...
Do you trust this plugin and allow code execution? [y/N]: y
[========================================] 100%
Installation complete.
Trust decision saved for future updates.步骤 3:验证信任在更新后持续存在
$ npx openclaw plugin update apple-pim-cli
Checking for updates...
Update available: 2.1.0 → 2.2.0
Running security scan...
ℹ️ Plugin has declared capabilities: executesCode
✓ Trust decision found from 2024-01-15
Updating to v2.2.0...
[========================================] 100%
Update complete.🧪 验证
验证 1:确认能力声明被正确解析
命令:
$ npx openclaw manifest inspect ./path/to/plugin --field capabilities预期输出:
{
"executesCode": true,
"reason": "Spawns native macOS Swift CLIs using EventKit..."
}
Status: ✓ Valid JSON structure
Scanner Compatibility: ✓ v2.x compatible退出码: 0
验证 2:安全扫描器产生知情同意而非硬阻止
命令:
$ npx openclaw plugin install apple-pim-cli 2>&1 | head -20预期输出(修复前):
✗ SECURITY FINDING [CRITICAL]
Rule: dangerous-exec
Plugin installation ABORTED.预期输出(修复后):
ℹ️ CAPABILITY DECLARATION DETECTED
executesCode: true
This plugin has declared its need to execute code.
Would you like to proceed with installation? [y/N]:退出码: 0(同意后)
验证 3:信任状态在配置中持久化
命令:
$ cat ~/.openclaw/plugins/apple-pim-cli/trust.json 2>/dev/null || echo "Not found"预期输出:
{
"pluginId": "apple-pim-cli",
"trusted": true,
"trustedAt": "2024-01-15T10:30:00Z",
"trustReason": "capability-declared:executesCode",
"expiresAt": null
}验证 4:自动化 CI/CD 管道测试
将此步骤添加到插件的 CI 管道中以验证能力声明:
# .github/workflows/test.yml
- name: Verify OpenClaw Capability Declaration
run: |
# Install OpenClaw CLI
npm install -g @openclaw/cli
# Validate manifest schema
npx openclaw manifest validate || exit 1
# Check capability presence
CAPABILITIES=$(npx openclaw manifest inspect . --field capabilities --json)
if echo "$CAPABILITIES" | grep -q "executesCode.*true"; then
echo "✓ Plugin correctly declares executesCode capability"
else
echo "✗ Plugin should declare executesCode if using child_process"
exit 1
fi
# Audit code for secure patterns
npx openclaw audit --plugin . --format json > audit-report.json
if grep -q '"violations":\[\]' audit-report.json; then
echo "✓ No security violations detected"
else
echo "✗ Security violations found:"
cat audit-report.json
exit 1
fi验证 5:端到端安装测试
命令:
$ npx openclaw plugin uninstall apple-pim-cli 2>/dev/null
$ echo "y" | npx openclaw plugin install apple-pim-cli --consent
$ npx openclaw plugin list --format json | jq '.plugins[] | select(.id == "apple-pim-cli")'预期输出:
{
"id": "apple-pim-cli",
"version": "2.1.0",
"installed": true,
"capabilities": {
"executesCode": true
},
"trustStatus": "trusted"
}⚠️ 常见陷阱
1. 发布不完整原因的能力声明
问题: 插件声明 executesCode: true 但没有有意义的 reason 字段。
错误示例:
{
"capabilities": {
"executesCode": true,
"reason": "yes"
}
}正确示例:
{
"capabilities": {
"executesCode": true,
"reason": "Spawns the 'swipl' Prolog interpreter to execute user queries. Binary path is hardcoded to /usr/bin/swipl; no shell interpolation."
}
}2. 在不需要时声明能力
问题: 某些插件作者可能预先添加能力声明,即使对于不需要 child_process 的插件也是如此。
影响: 用户对 executesCode 警告变得麻木,降低了其作为安全信号的有效性。
缓解措施: 仅在插件的运行时行为确实需要生成子进程时才声明 executesCode: true。
3. 使用 exec() 而不是 execFile() 或 spawn()
问题: 由于 shell 注入风险,安全扫描器可能会对 exec() 调用应用额外审查。
危险模式:
const { exec } = require('child_process');
exec(`parcel build ${inputPath}`, callback); // Shell injection risk安全模式:
const { execFile } = require('child_process');
execFile('parcel', ['build', inputPath], callback); // No shell interpolation4. 硬编码二进制路径与 PATH 解析
问题: 使用绝对路径的插件和使用 PATH 解析的二进制文件的插件可能会被不同地标记。
非最优方案:
execFile('/usr/local/bin/parcel', ['build', 'src']);推荐方案:
// Let the system resolve from PATH
execFile('parcel', ['build', 'src'], {
env: { ...process.env, PATH: process.env.PATH }
});5. 信任状态在大版本升级时不持久化
问题: 信任 v2.1.0 的用户可能需要在 v3.0.0 时重新确认,因为插件 ID 格式不同。
缓解措施: OpenClaw v2.x 使用 pluginId@majorVersion 作为信任密钥。确保您的插件在大版本之间保持相同的 ID 以保留信任状态。
6. Docker/容器环境误报
问题: 在 Docker 中运行时,child_process 检测可能会标记合法的操作,如 npm install 包装器。
环境特定行为:
# Running in Docker may produce different scanner results
$ docker run --rm node:20 npx openclaw plugin install some-plugin
# The container's node_modules may trigger different patterns缓解措施: 如果可用,使用 –ignore-pattern “node_modules/.bin/*",或提交环境特定的扫描器配置。
7. 插件包大小影响扫描时间
问题: 具有大量文件的大型插件可能会导致安全扫描阶段超时。
错误:
[DEBUG] Scanning 15,847 files...
[TIMEOUT] Security scan exceeded 30 second limit
[ERROR] Installation aborted: scan timeout缓解措施: 随插件提交 .openclawignore 文件,以将开发依赖项排除在扫描之外。
🔗 相关错误
错误代码和历史问题
SCANNER_E001— dangerous-exec(硬阻止)
本指南解决的主要错误。当检测到child_process使用但没有能力声明时发生。SCANNER_E002— arbitrary-code-injection
当扫描器检测到用于构造命令的字符串连接或模板字面量时触发。严重性高于dangerous-exec。SCANNER_E003— eval-usage
当检测到eval()、new Function()或类似的运行时代码构造时的关键发现。SCANNER_E004— network-exfiltration
当插件向未知端点发出网络请求时被标记。与dangerous-exec相关,因为两者都表示潜在的数据泄露。SCANNER_E005— filesystem-overreach
检测到插件在指定目录之外的文件系统操作。可能与恶意插件中的dangerous-exec同时出现。INSTALL_E101— manifest-missing
插件缺少有效的清单文件。可能阻止读取能力声明。INSTALL_E102— manifest-invalid-schema
能力声明存在但不符合预期架构。检查reason字段是否是非空字符串。TRUST_E201— consent-required
需要用户同意但 stdin 不是 TTY。使用--consent标志或--yes自动批准。TRUST_E202— trust-expired
先前授予的信任已过期。需要重新同意。
相关的 GitHub 问题
- Issue #1247 — 合法 CLI 包装器的安全扫描器误报
最初报告,识别了影响apple-pim-cli和类似插件的模式。 - Issue #1189 — 在清单架构中添加能力声明支持
提出本指南中实现的精确解决方案的功能请求。 - Issue #1102 — --dangerously-force-unsafe-install 标志具有误导性
报告"dangerously"术语不适合合法用例。 - Issue #1056 — 考虑为 child_process 采用基于路径的信任模型
讨论包括路径允许列表的替代方法。 - Issue #989 — 大型 monorepo 插件的扫描器超时
影响扫描完成的相关性能问题。
受影响的插件(社区报告)
apple-pim-cli— 通过 Swift CLI 进行 macOS 日历、提醒、联系人、邮件集成parcel-cli— 通过 Parcel CLI 进行包跟踪prolog-agent— SWI-Prolog 查询执行rust-analyzer-wrapped— Rust 语言服务器包装器dotnet-script— .NET 脚本执行