April 20, 2026

[危险执行模块导致插件安装被拦截] - 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 模块(spawnexecexecFile
  • 依赖本地 CLI 工具(parcel、esbuild、swipl 等)
  • 清单缺少 openclawcapabilities 配置部分

次要症状:令人警觉的术语

使用 –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 中实现的安全扫描阶段。该扫描器对插件代码执行静态分析,以检测潜在的危险操作。

故障序列

  1. 插件注册表查找: OpenClaw 从注册表检索插件清单
  2. 存档提取: 插件包被下载并提取到临时目录
  3. 安全扫描启动: SkillScanner 类实例化并开始文件遍历
  4. 静态分析: 每个 JavaScript/TypeScript 文件都被扫描以查找危险模式
  5. 模式匹配 - dangerous-exec: 扫描器检测到 require('child_process')import('child_process')
  6. 严重性分配: 该发现被分配 CRITICAL 严重性(硬编码)
  7. 策略执行: 安装策略指定 blockOnCritical: true
  8. 安装中止: 管道在不提取插件的情况下终止

代码路径分析

扫描器检测逻辑(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.jsonopenclaw.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 interpolation

4. 硬编码二进制路径与 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 脚本执行

依据与来源

本故障排除指南由 FixClaw 智能管线从社区讨论中自动合成。