# OneUptime: Synthetic Monitor RCE via exposed Playwright browser object

Low-privileged OneUptime project members could run custom Playwright code in a Node vm with live browser objects, reaching browserType().launch() to execute arbitrary commands on the probe host.

- Payout: Research
- Severity: critical
- Program: OneUptime
- Found by: maru1009
- Disclosed: 2026-03-07
- CVE: CVE-2026-30921
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-4j36-39gm-8vq8
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-4j36-39gm-8vq8
- Tags: area:web domain:web impact:internal-access impact:rce kind:research platform:ghsa sev:critical tech:nodejs technique:source-review vuln:rce vuln:sandbox-escape

**Target:** oneuptime-probe service executing user Playwright code in Node vm
**Root cause:** Untrusted Synthetic Monitor customCode is run in a Node vm that injects live host Playwright objects (browser, page); the proxy wrapper only blocks a few property names and forwards real method calls, so browser.browserType().launch() with attacker-controlled executablePath/args spawns arbitrary processes.
**Steps:**
1. Log in as any user with normal project membership.
2. Go to Monitors -> Create New Monitor and select Synthetic Monitor.
3. Paste Playwright code that derives a host Function via `Object.getOwnPropertyDescriptor(console, "log").value.constructor` and calls `process.getBuiltinModule("child_process").execSync("id")`.
4. Select a browser type (e.g. Chromium), screen type (Desktop), retry count 0.
5. Click Test Monitor and choose a probe; command output appears in Show More Details.
6. Alternatively save the malicious Synthetic Monitor for persistent scheduled RCE via FetchList.
**How found:** Reporter noted that Synthetic Monitor custom code runs in a Node vm with live Playwright browser/page objects injected, and that the proxy wrapper only blocks a small set of property names while forwarding real method calls with host this binding — so legitimate Playwright APIs like browserType().launch() remain reachable.
**Exploitation:** Attacker with ordinary project membership submits custom Playwright code through the Synthetic Monitor editor or Test Monitor flow. The probe polls the queued test, passes customCode to SyntheticMonitor.execute, which runs it in VMRunner's Node vm with live browser/page injected. Using the exposed browser object (or host Function constructor) the attacker spawns arbitrary executables on the probe container, gaining code execution with access to internal services, secrets, K8s metadata, DB/proxy credentials.
**Escalation:** One-shot RCE via Test Monitor can be made persistent by saving a malicious Synthetic Monitor, which is re-executed on every scheduled run.
**Insight:** When a sandbox injects live host capability objects (browser, page, clients) into untrusted code, enumerate every method on those objects for process-spawning or file/network primitives (e.g. Playwright BrowserType.launch with executablePath/args) — a property-name blocklist on a proxy is not a capability boundary.

