Resumen
El paquete npm publicado praisonai exporta una herramienta integrada de TypeScript denominada codeMode. El paquete describe esta herramienta como ejecutora de código en un entorno sandboxed, marca su capacidad como sandbox: true y la registra a través de la fachada pública de herramientas.
La implementación no crea ningún límite de aislamiento real. Aplica una pequeña lista de bloqueo basada en expresiones regulares, establece process y require como undefined dentro de un objeto JavaScript plano y, a continuación, ejecuta código controlado por el atacante mediante el constructor new Function del proceso anfitrión:
const fn = new Function('sandbox', `with (sandbox) { ${code} }`);
const result = fn(sandbox);
Dado que esto se ejecuta en el contexto V8 del proceso anfitrión, el código dentro de codeMode puede utilizar la cadena de prototipos de JavaScript para recuperar el constructor Function real:
({}).constructor.constructor('return process')()
Desde un script CommonJS normal, el objeto process recuperado expone process.mainModule.require. Esto elude los controles explícitos sobre require('fs') y require('child_process') y permite el acceso al sistema de archivos del anfitrión y la ejecución de subprocesos desde código que se suponía estaba sandboxed.
Detalles Técnicos
El código fuente actual indica que codeMode es una herramienta integrada del paquete y anuncia explícitamente un límite de sandbox:
src/praisonai-ts/src/tools/builtins/code-mode.ts
13: description: 'Execute code that can import and use other tools in a sandboxed environment',
24: capabilities: {
25: sandbox: true,
26: code: true,
28: packageName: 'praisonai',
85: description: 'Execute code in a sandboxed environment with access to imported tools. Write files, run code, and get results.',
El mismo archivo implementa la seguridad como una lista de bloqueo de patrones exactos en el código fuente:
src/praisonai-ts/src/tools/builtins/code-mode.ts
108: const blockedPatterns = [
109: /require\s*\(\s*['"']child_process['"']\s*\)/,
110: /require\s*\(\s*['"']fs['"']\s*\)/,
111: /import\s+.*from\s+['"']child_process['"']/,
112: /process\.exit/,
113: /eval\s*\(/,
A continuación intenta ocultar los globales peligrosos sobreponiendo nombres en un objeto normal:
src/praisonai-ts/src/tools/builtins/code-mode.ts
168: process: undefined,
169: require: undefined,
Finalmente, ejecuta el código no confiable en el proceso anfitrión usando new Function y with (sandbox):
src/praisonai-ts/src/tools/builtins/code-mode.ts
187: const fn = new Function(
188: 'sandbox',
189: `with (sandbox) { ${code} }`
190: );
191: const result = fn(sandbox);
Esto no es un sandbox. new Function no crea un contexto de seguridad separado, y el sombreado de variables no elimina el acceso a los constructores alcanzables a través de objetos JavaScript normales.
La herramienta es accesible a través del SDK npm público:
src/praisonai-ts/src/index.ts
117: airweaveSearch, codeMode,
src/praisonai-ts/src/tools/tools.ts
104: // Code Mode
105: registry.register(CODE_MODE_METADATA, createCodeModeTool as ToolFactory);
167: // Code Mode
168: codeMode: (config?: CodeModeConfig) => codeMode(config),
Por Qué Esto No Es Comportamiento Intencionado
Esto no es simplemente que el usuario pueda ejecutar código porque codeMode ejecuta código. La vulnerabilidad consiste en que el código descrito y expuesto explícitamente como sandboxed puede escapar las restricciones previstas.
La propia implementación demuestra que existe un límite de seguridad intencionado:
CODE_MODE_METADATA.capabilities.sandboxestrue.- La descripción de la herramienta indica que se ejecuta en un entorno sandboxed.
- El acceso directo a
fsychild_processestá explícitamente bloqueado. processyrequireestán explícitamente sombreados comoundefined.allowNetworktiene valor predeterminadofalse.- La configuración incluye controles relevantes para la seguridad como
blockedTools,allowedPaths,timeoutMsymaxMemoryMb.
La prueba de concepto demuestra que esas restricciones previstas funcionan para payloads ingenuos, pero fallan ante un escape estándar mediante la cadena de prototipos de JavaScript.
La documentación oficial de JavaScript y TypeScript de PraisonAI describe el paquete npm como un framework de agentes listo para producción que se instala con npm install praisonai. Los avisos públicos de PraisonAI califican escapes de sandbox comparables en Python como Críticos cuando el código suministrado por el usuario o por un LLM cruza desde un sandbox declarado hacia la ejecución en el anfitrión.
Prueba de Concepto
La prueba de concepto instala una versión publicada del paquete npm en un proyecto temporal y se ejecuta desde un archivo de script CommonJS real. Ejecutar desde un archivo es importante porque las aplicaciones Node normales exponen process.mainModule.require; node -e o stdin no siempre reproducen esa forma de despliegue.
Ejecución desde un checkout de reproducción local:
node poc/pov_poc.js 1.7.1
Resultado observado:
{
"package": "praisonai",
"version": "1.7.1",
"codeModeExported": true,
"directRequireFsControl": {
"stderr": "Blocked pattern detected: require\\s*\\(\\s*['\"]fs['\"]\\s*\\)",
"exitCode": 1,
"success": false,
"error": "Code contains blocked patterns for security"
},
"directChildProcessControl": {
"stderr": "Blocked pattern detected: require\\s*\\(\\s*['\"]child_process['\"]\\s*\\)",
"exitCode": 1,
"success": false,
"error": "Code contains blocked patterns for security"
},
"escapedProcessEnv": {
"output": "poc",
"exitCode": 0,
"success": true
},
"escapedFilesystem": {
"output": "fs-ok",
"exitCode": 0,
"success": true
},
"escapedCommand": {
"output": "poc",
"exitCode": 0,
"success": true
}
}
Interpretación:
- El
require('fs')directo está bloqueado. - El
require('child_process')directo está bloqueado. - El payload con el constructor Function recupera el
processdel anfitrión. - El proceso escapado lee una variable de entorno del anfitrión.
- El proceso escapado importa
fs. - El proceso escapado importa
child_processy ejecuta unprintfinofensivo.
La prueba de concepto no contacta ningún proveedor de LLM ni servicio externo tras la instalación del paquete npm. No modifica archivos del anfitrión ni ejecuta un comando destructivo.
Impacto
Un atacante que pueda suministrar código a codeMode puede escapar del sandbox anunciado y ejecutar con los privilegios del proceso Node.js de PraisonAI.
Los vectores de entrada realistas incluyen:
- Una aplicación que expone
codeModecomo herramienta de agente a usuarios finales. - Un flujo LLM o de llamada a herramientas donde el contenido controlado por prompt alcanza el parámetro
code. - Integraciones MCP o de registro de herramientas que hacen que la herramienta integrada
codeModesea invocable. - Cualquier servicio multitenant que dependa de
codeModepara ejecutar de forma segura JavaScript generado por usuarios o modelos.
El impacto tras el escape incluye:
- Lectura de variables de entorno del proceso, incluyendo claves de API y tokens de servicio.
- Lectura de archivos disponibles para el proceso Node.
- Lanzamiento de subprocesos mediante
child_process. - Escritura o modificación de archivos a través de las API del sistema de archivos del anfitrión.
- Terminación o agotamiento de recursos del proceso anfitrión.
Corrección Sugerida
No se debe usar new Function en el proceso anfitrión junto con listas de bloqueo de código fuente como sandbox.
Dirección de corrección recomendada:
- Deshabilitar o marcar claramente el
codeModede npm como inseguro hasta que exista un límite de aislamiento real. - Ejecutar el código no confiable en un proceso de sistema operativo separado, contenedor, worker isolate o límite similar con un usuario restringido, entorno mínimo, directorio de trabajo temporal, sin secretos heredados y con IPC explícito para las llamadas a herramientas permitidas.
- Aplicar
allowNetwork,allowedPaths,timeoutMs,maxMemoryMb,allowedToolsyblockedToolsen ese límite en lugar de mediante el escaneo de cadenas de código fuente. - No depender únicamente de
node:vmpara código no confiable. La documentación de Node.js indica explícitamente que el módulovmno es un mecanismo de seguridad. - Añadir pruebas de regresión para:
- Controles de bloqueo de
require('fs')yrequire('child_process')directos. - Bloqueo de
({}).constructor.constructor('return process')(). - Indisponibilidad de
process.mainModule.require('fs'). - Indisponibilidad de
process.mainModule.require('child_process'). - Variables de entorno del anfitrión no disponibles salvo que se pasen explícitamente.
- IPC de llamadas a herramientas que sigue funcionando para herramientas permitidas.
- Controles de bloqueo de
Si los mantenedores necesitan una mitigación de emergencia antes de que exista un sandbox real, se recomienda rechazar la ejecución de codeMode a menos que el llamador opte explícitamente por la opción de ejecución JavaScript insegura en el anfitrión, con documentación clara de que puede acceder al proceso Node completo.
Paquetes y Versiones Afectadas
- Repositorio:
MervinPraison/PraisonAI - Ecosistema:
npm - Paquete:
praisonai - Componente:
src/praisonai-ts/src/tools/builtins/code-mode.ts - Versión npm verificada:
1.7.1 - Commit de
origin/mainverificado:1ad58ca02975ff1398efeda694ea2ab78f20cf3e
Rango afectado confirmado:
>= 1.4.0, <= 1.7.1
Límite inferior: la versión 1.3.6 no exporta codeMode y no incluye dist/tools/builtins/code-mode.js.
No se conoce ninguna versión npm corregida en el momento de este informe.
Barrido de Versiones
El barrido incluido instala versiones npm seleccionadas y ejecuta la misma forma vulnerable desde un archivo de script:
node poc/version_sweep_poc.js
Resultado observado:
1.3.6: codeModeExported=false, hasDistCodeMode=false
1.4.0: directRequireFsBlocked=true, escapeProcessEnv=true, escapeFilesystem=true, escapeCommand=true
1.5.4: directRequireFsBlocked=true, escapeProcessEnv=true, escapeFilesystem=true, escapeCommand=true
1.6.0: directRequireFsBlocked=true, escapeProcessEnv=true, escapeFilesystem=true, escapeCommand=true
1.7.0: directRequireFsBlocked=true, escapeProcessEnv=true, escapeFilesystem=true, escapeCommand=true
1.7.1: directRequireFsBlocked=true, escapeProcessEnv=true, escapeFilesystem=true, escapeCommand=true
El historial de Git para el archivo TypeScript apunta a la integración de la versión 1.4.0:
56f36e25 feat: bump version to 1.4.0 and add AI SDK integration dependencies
2bad9a50 feat: bump version to 1.4.0 and add AI SDK integration dependencies
Historial de Avisos
Los avisos relacionados más cercanos tienen alcance Python o PyPI y no cubren esta implementación TypeScript de npm:
GHSA-qf73-2hrx-xprp/CVE-2026-39888:pip:praisonaiagentscon traversal de frames enexecute_code()dentro de un sandbox de subproceso Python.GHSA-4mr5-g6f9-cfrh/CVE-2026-47392:pip:praisonaicon escape de sandbox Python enexecute_code()medianteprint.__self__.- Otros avisos publicados de PraisonAI cubren
execute_codeen Python,SubprocessSandbox, Sandlock o puentes CLI.
Este informe es distinto porque apunta a: ecosistema npm, paquete praisonai, componente code-mode.ts, causa raíz de new Function en contexto anfitrión con lista de bloqueo y sombreado de nombres, y rango afectado >= 1.4.0, <= 1.7.1.
