# npm PraisonAI codeMode sandbox escape via Function constructor

npm praisonai codeMode claims a sandbox but runs code via host new Function, letting a prototype-chain payload recover process and reach fs/child_process.

- Payout: Research
- Severity: critical
- Program: PraisonAI
- Found by: rexpository
- Disclosed: 2026-06-18
- CVE: CVE-2026-57138
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-vmmj-pfw7-fjwp
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-vmmj-pfw7-fjwp
- Tags: area:oss domain:oss impact:data-leak impact:internal-access impact:rce kind:research platform:ghsa sev:critical tech:nodejs technique:incomplete-fix technique:source-review vuln:rce vuln:sandbox-escape

**Target:** npm package praisonai codeMode built-in tool (src/praisonai-ts/src/tools/builtins/code-mode.ts)
**Root cause:** codeMode enforces security with a regex blocklist plus shadowing process/require as undefined in a plain object, then executes untrusted code with the host-process `new Function` under `with (sandbox)`, which is not an isolation boundary.
**Steps:**
1. Install affected npm praisonai (>=1.4.0, <=1.7.1) and run from a real CommonJS script file so process.mainModule.require exists.
2. Confirm controls: `require('fs')` and `require('child_process')` are rejected with 'Blocked pattern detected'.
3. Submit payload `({}).constructor.constructor('return process')()` to recover the host process object via the prototype chain.
4. Use `process.mainModule.require('fs')` to read host files and `process.mainModule.require('child_process')` to spawn a subprocess (e.g. printf).
5. Observe escaped env read, fs-ok, and command output with exitCode 0.
**How found:** Reporter read code-mode.ts, noticed the tool advertises sandbox:true and blocks fs/child_process by regex while shadowing process/require as undefined, recognized that `new Function` runs in the host V8 context and that shadowing a plain object does not remove constructors reachable via the prototype chain, then validated with a script-file PoV and a version sweep.
**Exploitation:** Attacker supplies code to codeMode (end-user tool exposure, LLM/tool-call flow, MCP/tool-registry, or multi-tenant service). A single payload recovers host process via the Function constructor, then uses process.mainModule.require to import fs and child_process, reading env vars/API keys, reading and writing files, and spawning subprocesses with the Node process privileges.
**Insight:** When a JS 'sandbox' shadows globals in a plain object and uses `with`, the prototype chain still yields the real Function constructor: `({}).constructor.constructor('return process')()`. Also run PoCs from a real CommonJS file, not `node -e`, since process.mainModule.require only exists in that deployment shape.

## Proof of concept (copied exactly from the original report)

**Function constructor prototype-chain escape payload**

```
({}).constructor.constructor('return process')()
```

**Vulnerable new Function execution with sandbox**

```
const fn = new Function('sandbox', `with (sandbox) { ${code} }`);
const result = fn(sandbox);
```

**PoV reproduction command**

```
node poc/pov_poc.js 1.7.1
```

