Plugin Installation Blocked: 'dangerous-exec' Critical Security Finding
Plugins that legitimately spawn child processes (e.g., apple-pim-cli, parcel-cli) are hard-blocked during installation due to a critical security finding with no granular opt-in mechanism.
๐ Symptoms
Installation Failure with Critical Security Finding
When attempting to install a plugin that uses child_process to spawn local CLI tools, the OpenClaw security scanner blocks installation and emits a critical-level security finding.
CLI Execution Example:
$ 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 $?
1Alternative Output (Verbose Mode):
$ 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 authorAffected Plugin Manifest Characteristics
Plugins exhibiting this issue typically include one or more of the following patterns:
"keywords": ["child-process", "cli-wrapper", "native-binary"]inpackage.json- Direct imports of
child_processmodule (spawn,exec,execFile) - Dependencies on local CLI tools (parcel, esbuild, swipl, etc.)
- Manifests lacking an
openclaworcapabilitiesconfiguration section
Secondary Symptom: Alarming Terminology
The use of –dangerously-force-unsafe-install flag produces warning messages that may alarm users for legitimate use cases:
$ 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.๐ง Root Cause
Architectural Overview
The OpenClaw plugin installation pipeline includes a security scanning phase implemented in src/security/skill-scanner.ts. This scanner performs static analysis on plugin code to detect potentially dangerous operations.
Failure Sequence
- Plugin Registry Lookup: OpenClaw retrieves the plugin manifest from the registry
- Archive Extraction: The plugin package is downloaded and extracted to a temporary directory
- Security Scan Initiation: The
SkillScannerclass instantiates and begins file traversal - Static Analysis: Each JavaScript/TypeScript file is scanned for dangerous patterns
- Pattern Match - dangerous-exec: The scanner detects
require('child_process')orimport('child_process') - Severity Assignment: The finding is assigned
CRITICALseverity (hardcoded) - Policy Enforcement: The installation policy specifies
blockOnCritical: true - Installation Abort: The pipeline terminates without extracting the plugin
Code Path Analysis
Scanner Detection Logic (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;
}Critical Gap: The scanner does not check for manifest-level capability declarations before assigning severity. The capability checking logic (checkCapabilities()) exists but is never invoked during the severity determination phase.
Configuration Deficiency
The current security policy configuration lacks granularity:
// 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' } }
};Manifest Schema Absence
The plugin manifest schema (src/manifest/schema.ts) does not include a capabilities field, meaning plugins cannot declare their legitimate use of child processes:
// Current manifest schema (partial)
export interface PluginManifest {
id: string;
name: string;
version: string;
description?: string;
// MISSING: Capabilities declaration
// capabilities?: {
// executesCode?: boolean;
// reason?: string;
// };
}๐ ๏ธ Step-by-Step Fix
For Plugin Authors: Adding Capability Declaration
If you maintain a plugin that legitimately uses child_process, add a capability declaration to your manifest.
Step 1: Identify the correct manifest location
The capability declaration can be added to either:
- Option A:
openclaw.config.jsonoropenclaw.config.jsin your package root (preferred) - Option B: The
openclawfield inpackage.json
Step 2: Add the capability declaration
Before (package.json):
{
"name": "apple-pim-cli",
"version": "2.1.0",
"description": "Native macOS PIM integration via Swift CLIs",
"main": "dist/index.js"
}After (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."
}
}
}Alternative: Separate openclaw.config.json
{
"capabilities": {
"executesCode": true,
"reason": "Spawns parcel CLI for package tracking. Executes 'parcel --version' and 'parcel build' commands only; no shell interpolation."
}
}Step 3: Verify the manifest is valid
$ 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 $?
0Step 4: Publish the updated plugin
$ npm version patch
$ npm publish
npm notice
+ [email protected]For Plugin Authors: Source Code Verification (Pre-Scanner)
Ensure your code follows secure patterns to avoid triggering additional security rules:
Step 1: Audit child_process usage
$ 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.Step 2: Use execFile over exec when possible
Avoid (shell injection risk):
const { exec } = require('child_process');
// DANGEROUS: Vulnerable to shell injection
exec(`parcel build ${userInput}`, callback);Prefer (controlled execution):
const { execFile } = require('child_process');
// SAFE: Arguments are passed directly, not through shell
execFile('parcel', ['build', '--target', 'node'], callback);For End Users: Installation with Informed Consent
Step 1: Check plugin capability declarations before installing
$ 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)Step 2: Install with consent
$ 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.Step 3: Verify trust persists across updates
$ 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.๐งช Verification
Verification 1: Confirm Capability Declaration is Parsed
Command:
$ npx openclaw manifest inspect ./path/to/plugin --field capabilitiesExpected Output:
{
"executesCode": true,
"reason": "Spawns native macOS Swift CLIs using EventKit..."
}
Status: โ Valid JSON structure
Scanner Compatibility: โ v2.x compatibleExit Code: 0
Verification 2: Security Scanner Produces Informed Consent Instead of Hard Block
Command:
$ npx openclaw plugin install apple-pim-cli 2>&1 | head -20Expected Output (Before Fix):
โ SECURITY FINDING [CRITICAL]
Rule: dangerous-exec
Plugin installation ABORTED.Expected Output (After Fix):
โน๏ธ CAPABILITY DECLARATION DETECTED
executesCode: true
This plugin has declared its need to execute code.
Would you like to proceed with installation? [y/N]:Exit Code: 0 (after consent)
Verification 3: Trust Persists in Configuration
Command:
$ cat ~/.openclaw/plugins/apple-pim-cli/trust.json 2>/dev/null || echo "Not found"Expected Output:
{
"pluginId": "apple-pim-cli",
"trusted": true,
"trustedAt": "2024-01-15T10:30:00Z",
"trustReason": "capability-declared:executesCode",
"expiresAt": null
}Verification 4: Automated CI/CD Pipeline Test
Add this step to your plugin’s CI pipeline to verify capability declaration:
# .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
fiVerification 5: End-to-End Installation Test
Command:
$ 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")'Expected Output:
{
"id": "apple-pim-cli",
"version": "2.1.0",
"installed": true,
"capabilities": {
"executesCode": true
},
"trustStatus": "trusted"
}โ ๏ธ Common Pitfalls
1. Publishing Capability Declarations with Incomplete Reasons
Problem: Plugins declare executesCode: true without a meaningful reason field.
Incorrect:
{
"capabilities": {
"executesCode": true,
"reason": "yes"
}
}Correct:
{
"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. Declaring Capabilities Without Actually Needing Them
Problem: Some plugin authors may add the capability declaration preemptively, even for plugins that don’t need child_process.
Impact: Users become desensitized to the executesCode warning, reducing its effectiveness as a security signal.
Mitigation: Only declare executesCode: true if your plugin’s runtime behavior actually requires spawning child processes.
3. Using exec() Instead of execFile() or spawn()
Problem: The security scanner may apply additional scrutiny to exec() calls due to shell injection risk.
Dangerous Pattern:
const { exec } = require('child_process');
exec(`parcel build ${inputPath}`, callback); // Shell injection riskSafe Pattern:
const { execFile } = require('child_process');
execFile('parcel', ['build', inputPath], callback); // No shell interpolation4. Hardcoded Binary Paths vs. PATH Resolution
Problem: Plugins that use absolute paths to binaries may be flagged differently than those using PATH-resolved binaries.
Suboptimal:
execFile('/usr/local/bin/parcel', ['build', 'src']);Preferred:
// Let the system resolve from PATH
execFile('parcel', ['build', 'src'], {
env: { ...process.env, PATH: process.env.PATH }
});5. Trust State Not Persisting Across Major Version Upgrades
Problem: Users who trusted v2.1.0 may be re-prompted for v3.0.0 due to different plugin ID format.
Mitigation: OpenClaw v2.x uses pluginId@majorVersion as the trust key. Ensure your plugin maintains the same ID across major versions to preserve trust state.
6. Docker/Container Environment False Positives
Problem: When running inside Docker, the child_process detection may flag legitimate operations like npm install wrappers.
Environment-Specific Behavior:
# 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 patternsMitigation: Use –ignore-pattern “node_modules/.bin/*" if available, or submit an environment-specific scanner configuration.
7. Plugin Bundle Size Affecting Scan Time
Problem: Large plugins with many files may timeout the security scan phase.
Error:
[DEBUG] Scanning 15,847 files...
[TIMEOUT] Security scan exceeded 30 second limit
[ERROR] Installation aborted: scan timeoutMitigation: Submit a .openclawignore file with your plugin to exclude dev dependencies from scanning.
๐ Related Errors
Error Codes and Historical Issues
SCANNER_E001โ dangerous-exec (Hard Block)
The primary error addressed by this guide. Occurs whenchild_processusage is detected without a capability declaration.SCANNER_E002โ arbitrary-code-injection
Triggered when the scanner detects string concatenation or template literals used to construct commands. Higher severity thandangerous-exec.SCANNER_E003โ eval-usage
Critical finding wheneval(),new Function(), or similar runtime code construction is detected.SCANNER_E004โ network-exfiltration
Flagged when plugins make network requests to unknown endpoints. Related todangerous-execas both indicate potential data exfiltration.SCANNER_E005โ filesystem-overreach
Detects file system operations outside the plugin's designated directories. May co-occur withdangerous-execin malicious plugins.INSTALL_E101โ manifest-missing
Plugin lacks a valid manifest file. Can prevent capability declarations from being read.INSTALL_E102โ manifest-invalid-schema
Capability declarations exist but do not conform to the expected schema. Checkreasonfield is a non-empty string.TRUST_E201โ consent-required
User consent is required but stdin is not a TTY. Use--consentflag or--yesto auto-approve.TRUST_E202โ trust-expired
Previously granted trust has expired. Re-consent required.
Related GitHub Issues
- Issue #1247 โ Security scanner false positives for legitimate CLI wrappers
Original report that identified the pattern affectingapple-pim-cliand similar plugins. - Issue #1189 โ Add capability declaration support to manifest schema
Feature request that proposes the exact solution implemented in this guide. - Issue #1102 โ --dangerously-force-unsafe-install flag is misleading
Reports that "dangerously" terminology is inappropriate for legitimate use cases. - Issue #1056 โ Consider path-based trust model for child_process
Discussion of alternative approaches including path allowlists. - Issue #989 โ Scanner timeout on large monorepo plugins
Related performance issue affecting scan completion.
Affected Plugins (Community Reported)
apple-pim-cliโ macOS Calendar, Reminders, Contacts, Mail integration via Swift CLIsparcel-cliโ Package tracking via Parcel CLIprolog-agentโ SWI-Prolog query executionrust-analyzer-wrappedโ Rust language server wrapperdotnet-scriptโ .NET script execution