Instalación de plugin bloqueada debido a hallazgo de seguridad crítico en 'dangerous-exec' sin mecanismo de aceptación granular - Plugin Installation Blocked: 'dangerous-exec' Critical Security Finding
Los plugins que legitimamente generan procesos secundarios (ej., apple-pim-cli, parcel-cli) están bloqueados durante la instalación debido a un hallazgo de seguridad crítico sin ningún mecanismo de aceptación granular.
🔍 Síntomas
Error de instalación con hallazgo de seguridad crítico
Al intentar instalar un plugin que utiliza child_process para ejecutar herramientas CLI locales, el escáner de seguridad OpenClaw bloquea la instalación y emite un hallazgo de seguridad de nivel crítico.
Ejemplo de ejecución 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 $?
1Salida alternativa (Modo detallado):
$ 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 authorCaracterísticas del manifiesto del plugin afectado
Los plugins que presentan este problema típicamente incluyen uno o más de los siguientes patrones:
"keywords": ["child-process", "cli-wrapper", "native-binary"]enpackage.json- Importaciones directas del módulo
child_process(spawn,exec,execFile) - Dependencias de herramientas CLI locales (parcel, esbuild, swipl, etc.)
- Manifiestos que carecen de una sección de configuración
openclawocapabilities
Síntoma secundario: Terminología alarmante
El uso del indicador –dangerously-force-unsafe-install produce mensajes de advertencia que pueden alarmar a los usuarios para casos de uso legítimos:
$ 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.🧠 Causa raíz
Descripción general de la arquitectura
El pipeline de instalación de plugins de OpenClaw incluye una fase de análisis de seguridad implementada en src/security/skill-scanner.ts. Este escáner realiza análisis estático en el código del plugin para detectar operaciones potencialmente peligrosas.
Secuencia de falla
- Consulta al registro de plugins: OpenClaw recupera el manifiesto del plugin del registro
- Extracción del archivo: El paquete del plugin se descarga y extrae a un directorio temporal
- Inicio del análisis de seguridad: La clase
SkillScannerse instancia e inicia el recorrido de archivos - Análisis estático: Cada archivo JavaScript/TypeScript se analiza en busca de patrones peligrosos
- Coincidencia de patrón - dangerous-exec: El escáner detecta
require('child_process')oimport('child_process') - Asignación de severidad: Al hallazgo se le asigna severidad
CRITICAL(codificada) - Aplicación de política: La política de instalación especifica
blockOnCritical: true - Aborto de instalación: El pipeline termina sin extraer el plugin
Análisis de la ruta de código
Lógica de detección del escáner (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;
}Brecha crítica: El escáner no verifica las declaraciones de capacidades a nivel de manifiesto antes de asignar la severidad. La lógica de verificación de capacidades (checkCapabilities()) existe pero nunca se invoca durante la fase de determinación de severidad.
Deficiencia de configuración
La configuración actual de la política de seguridad carece de granularidad:
// 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' } }
};Ausencia del esquema de manifiesto
El esquema del manifiesto del plugin (src/manifest/schema.ts) no incluye un campo capabilities, lo que significa que los plugins no pueden declarar su uso legítimo de 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;
// };
}🛠️ Solución paso a paso
Para autores de plugins: Agregar declaración de capacidades
Si mantienes un plugin que usa legítimamente child_process, agrega una declaración de capacidades a tu manifiesto.
Paso 1: Identificar la ubicación correcta del manifiesto
La declaración de capacidades se puede agregar a cualquiera de las siguientes ubicaciones:
- Opción A:
openclaw.config.jsonoopenclaw.config.jsen la raíz de tu paquete (preferido) - Opción B: El campo
openclawenpackage.json
Paso 2: Agregar la declaración de capacidades
Antes (package.json):
{
"name": "apple-pim-cli",
"version": "2.1.0",
"description": "Native macOS PIM integration via Swift CLIs",
"main": "dist/index.js"
}Después (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."
}
}
}Alternativa: archivo openclaw.config.json separado
{
"capabilities": {
"executesCode": true,
"reason": "Spawns parcel CLI for package tracking. Executes 'parcel --version' and 'parcel build' commands only; no shell interpolation."
}
}Paso 3: Verificar que el manifiesto sea válido
$ 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 $?
0Paso 4: Publicar el plugin actualizado
$ npm version patch
$ npm publish
npm notice
+ [email protected]Para autores de plugins: Verificación del código fuente (Pre-escáner)
Asegúrate de que tu código siga patrones seguros para evitar activar reglas de seguridad adicionales:
Paso 1: Auditar el uso de 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.Paso 2: Usar execFile en lugar de exec cuando sea posible
Evitar (riesgo de inyección de shell):
const { exec } = require('child_process');
// DANGEROUS: Vulnerable to shell injection
exec(`parcel build ${userInput}`, callback);Preferir (ejecución controlada):
const { execFile } = require('child_process');
// SAFE: Arguments are passed directly, not through shell
execFile('parcel', ['build', '--target', 'node'], callback);Para usuarios finales: Instalación con consentimiento informado
Paso 1: Verificar las declaraciones de capacidades del plugin antes de instalar
$ 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)Paso 2: Instalar con consentimiento
$ 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.Paso 3: Verificar que la confianza persiste entre actualizaciones
$ 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.🧪 Verificación
Verificación 1: Confirmar que la declaración de capacidades se analiza correctamente
Comando:
$ npx openclaw manifest inspect ./path/to/plugin --field capabilitiesSalida esperada:
{
"executesCode": true,
"reason": "Spawns native macOS Swift CLIs using EventKit..."
}
Status: ✓ Valid JSON structure
Scanner Compatibility: ✓ v2.x compatibleCódigo de salida: 0
Verificación 2: El escáner de seguridad produce consentimiento informado en lugar de bloqueo duro
Comando:
$ npx openclaw plugin install apple-pim-cli 2>&1 | head -20Salida esperada (Antes de la corrección):
✗ SECURITY FINDING [CRITICAL]
Rule: dangerous-exec
Plugin installation ABORTED.Salida esperada (Después de la corrección):
ℹ️ CAPABILITY DECLARATION DETECTED
executesCode: true
This plugin has declared its need to execute code.
Would you like to proceed with installation? [y/N]:Código de salida: 0 (después del consentimiento)
Verificación 3: La confianza persiste en la configuración
Comando:
$ cat ~/.openclaw/plugins/apple-pim-cli/trust.json 2>/dev/null || echo "Not found"Salida esperada:
{
"pluginId": "apple-pim-cli",
"trusted": true,
"trustedAt": "2024-01-15T10:30:00Z",
"trustReason": "capability-declared:executesCode",
"expiresAt": null
}Verificación 4: Prueba de pipeline CI/CD automatizado
Agrega este paso al pipeline CI de tu plugin para verificar la declaración de capacidades:
# .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
fiVerificación 5: Prueba de instalación de extremo a extremo
Comando:
$ 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")'Salida esperada:
{
"id": "apple-pim-cli",
"version": "2.1.0",
"installed": true,
"capabilities": {
"executesCode": true
},
"trustStatus": "trusted"
}⚠️ Errores comunes
1. Publicar declaraciones de capacidades con razones incompletas
Problema: Los plugins declaran executesCode: true sin un campo reason significativo.
Incorrecto:
{
"capabilities": {
"executesCode": true,
"reason": "yes"
}
}Correcto:
{
"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. Declarar capacidades sin necesitarlas realmente
Problema: Algunos autores de plugins pueden agregar la declaración de capacidades de manera preventiva, incluso para plugins que no necesitan child_process.
Impacto: Los usuarios se desensibilizan ante la advertencia de executesCode, reduciendo su efectividad como señal de seguridad.
Mitigación: Solo declara executesCode: true si el comportamiento en tiempo de ejecución de tu plugin realmente requiere ejecutar procesos hijos.
3. Usar exec() en lugar de execFile() o spawn()
Problema: El escáner de seguridad puede aplicar escrutinio adicional a las llamadas exec() debido al riesgo de inyección de shell.
Patrón peligroso:
const { exec } = require('child_process');
exec(`parcel build ${inputPath}`, callback); // Shell injection riskPatrón seguro:
const { execFile } = require('child_process');
execFile('parcel', ['build', inputPath], callback); // No shell interpolation4. Rutas de binarios hardcodeadas vs. resolución de PATH
Problema: Los plugins que usan rutas absolutas a binarios pueden ser marcados de manera diferente que aquellos que usan binarios resueltos mediante PATH.
Subóptimo:
execFile('/usr/local/bin/parcel', ['build', 'src']);Preferido:
// Let the system resolve from PATH
execFile('parcel', ['build', 'src'], {
env: { ...process.env, PATH: process.env.PATH }
});5. El estado de confianza no persiste entre actualizaciones de versión mayor
Problema: Los usuarios que confiaron en v2.1.0 pueden ser re-preguntados para v3.0.0 debido a un formato de ID de plugin diferente.
Mitigación: OpenClaw v2.x usa pluginId@majorVersion como clave de confianza. Asegúrate de que tu plugin mantenga el mismo ID entre versiones mayores para preservar el estado de confianza.
6. Falsos positivos en entornos Docker/Contenedor
Problema: Cuando se ejecuta dentro de Docker, la detección de child_process puede marcar operaciones legítimas como contenedores de npm install.
Comportamiento específico del entorno:
# 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 patternsMitigación: Usa –ignore-pattern “node_modules/.bin/*" si está disponible, o envía una configuración de escáner específica del entorno.
7. El tamaño del paquete del plugin afecta el tiempo de escaneo
Problema: Los plugins grandes con muchos archivos pueden causar timeout en la fase de escaneo de seguridad.
Error:
[DEBUG] Scanning 15,847 files...
[TIMEOUT] Security scan exceeded 30 second limit
[ERROR] Installation aborted: scan timeoutMitigación: Envía un archivo .openclawignore con tu plugin para excluir las dependencias de desarrollo del escaneo.
🔗 Errores relacionados
Códigos de error y problemas históricos
SCANNER_E001— dangerous-exec (Bloqueo duro)
El error principal abordado por esta guía. Ocurre cuando se detecta uso dechild_processsin una declaración de capacidades.SCANNER_E002— arbitrary-code-injection
Se activa cuando el escáner detecta concatenación de cadenas o literales de plantilla usados para construir comandos. Mayor severidad quedangerous-exec.SCANNER_E003— eval-usage
Hallazgo crítico cuando se detectaeval(),new Function()o construcción similar de código en tiempo de ejecución.SCANNER_E004— network-exfiltration
Se marca cuando los plugins realizan solicitudes de red a endpoints desconocidos. Relacionado condangerous-execya que ambos indican posible exfiltración de datos.SCANNER_E005— filesystem-overreach
Detecta operaciones de sistema de archivos fuera de los directorios designados del plugin. Puede ocurrir junto condangerous-execen plugins maliciosos.INSTALL_E101— manifest-missing
El plugin carece de un archivo de manifiesto válido. Puede impedir que se lean las declaraciones de capacidades.INSTALL_E102— manifest-invalid-schema
Las declaraciones de capacidades existen pero no se ajustan al esquema esperado. Verifica que el camporeasonsea una cadena no vacía.TRUST_E201— consent-required
Se requiere consentimiento del usuario pero stdin no es un TTY. Usa el indicador--consento--yespara aprobar automáticamente.TRUST_E202— trust-expired
La confianza otorgada anteriormente ha expirado. Se requiere re-consentimiento.
Issues de GitHub relacionados
- Issue #1247 — Security scanner false positives for legitimate CLI wrappers
Reporte original que identificó el patrón que afecta aapple-pim-cliy plugins similares. - Issue #1189 — Add capability declaration support to manifest schema
Solicitud de característica que propone la solución exacta implementada en esta guía. - Issue #1102 — --dangerously-force-unsafe-install flag is misleading
Reporta que la terminología "dangerously" es inapropiada para casos de uso legítimos. - Issue #1056 — Consider path-based trust model for child_process
Discusión de enfoques alternativos incluyendo listas de permitidos basadas en rutas. - Issue #989 — Scanner timeout on large monorepo plugins
Problema de rendimiento relacionado que afecta la finalización del escaneo.
Plugins afectados (Reportados por la comunidad)
apple-pim-cli— Integración de Calendario, Recordatorios, Contactos y Mail de macOS mediante CLIs de Swiftparcel-cli— Seguimiento de paquetes mediante Parcel CLIprolog-agent— Ejecución de consultas SWI-Prologrust-analyzer-wrapped— Contenedor del servidor de lenguaje Rustdotnet-script— Ejecución de scripts .NET