# CVE-2026-30921: @oneuptime/common — Fixed in 10.0.20

📦

📦 npm

Not in CISA KEV

CRITICAL severity

# CVE-2026-30921 — @oneuptime/common

CRITICAL 

CVE-2026-30921 is a critical-severity (CVSS 9.9) CWE-749 vulnerability in @oneuptime/common. A fix is available for @oneuptime/common — see the affected versions and patch details below.

OneUptime Synthetic Monitor RCE via exposed Playwright browser object

Also known as[GHSA-4j36-39gm-8vq8](/vulnerability/GHSA-4j36-39gm-8vq8)

Published

Mar 9, 2026

Updated

Oct 28, 2026

Affected

1 pkg

Patched

1 / 1

Exploits

None indexed

Exploitation data as of Nov 8, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

## Exploitation Status

### Proof-of-concept exploit code exists

-   CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
-   A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-30921.

## EPSS Exploitation Probability

[via FIRST.org ↗](https://www.first.org/epss/)

0.5%probability of exploitation in next 30 days

Lower Risk+0.03%

Lower risk than most CVEs42th percentile — riskier than 42% of all scored CVEsHighest risk

0.00%0.34%0.68%1.02%0.0%0.5%May 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from [FIRST.org EPSS](https://www.first.org/epss/).

## How urgent is this, really

## Where this sits among everything scored

## Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

0other npm packages depend on this — each one inherits the vulnerability until it's patched upstream

`@oneuptime/common`npm

14Kdownloads / week

## Description

Summary

OneUptime Synthetic Monitors allow low-privileged project users to submit custom Playwright code that is executed on the `oneuptime-probe` service. In the current implementation, this untrusted code is run inside Node's `vm` and is given live host Playwright objects such as `browser` and `page`.

This creates a distinct server-side RCE primitive: the attacker does not need the classic `this.constructor.constructor(...)` sandbox escape. Instead, the attacker can directly use the injected Playwright `browser` object to reach `browser.browserType().launch(...)` and spawn an arbitrary executable on the probe host/container.

This appears to be a separate issue from the previously published `node:vm(GHSA-h343-gg57-2q67)` breakout advisory because the root cause here is exposure of a dangerous host capability object to untrusted code, not prototype-chain access to `process`.

### Details

A normal project member can create or edit monitors and monitor tests:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Models/DatabaseModels/Monitor.ts#L45-L78](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Models/DatabaseModels/Monitor.ts#L45-L78)
-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Models/DatabaseModels/MonitorTest.ts#L27-L60](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Models/DatabaseModels/MonitorTest.ts#L27-L60)

The dashboard exposes a Playwright code editor for Synthetic Monitors and allows the user to queue a test run:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/App/FeatureSet/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx#L861-L918](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/App/FeatureSet/Dashboard/src/Components/Form/Monitor/MonitorStep.tsx#L861-L918)
-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/App/FeatureSet/Dashboard/src/Components/Form/Monitor/MonitorTest.tsx#L66-L84](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/App/FeatureSet/Dashboard/src/Components/Form/Monitor/MonitorTest.tsx#L66-L84)

The probe worker polls queued monitor tests and executes them:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Jobs/Monitor/FetchMonitorTest.ts#L55-L85](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Jobs/Monitor/FetchMonitorTest.ts#L55-L85)

For `MonitorType.SyntheticMonitor`, the user-controlled `customCode` is passed into `SyntheticMonitor.execute(...)`:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Utils/Monitors/Monitor.ts#L323-L338](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Utils/Monitors/Monitor.ts#L323-L338)

`SyntheticMonitor.execute(...)` then runs that code through `VMRunner.runCodeInNodeVM(...)` and injects the live Playwright `browser` and `page` objects into the VM context:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Utils/Monitors/MonitorTypes/SyntheticMonitor.ts#L156-L168](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Utils/Monitors/MonitorTypes/SyntheticMonitor.ts#L156-L168)

`VMRunner.runCodeInNodeVM(...)` creates a Node `vm` context and exposes host objects into it, including the additional context objects:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Server/Utils/VM/VMRunner.ts#L323-L405](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Common/Server/Utils/VM/VMRunner.ts#L323-L405)

The proxy wrapper blocks only a small set of property names and still forwards normal method calls with the real host `this` binding. Because of that, untrusted monitor code can still use legitimate Playwright methods on the injected `browser` object.

That is enough for code execution because Playwright's `Browser` exposes `browserType()`, and `BrowserType.launch()` accepts attacker-controlled process launch options such as `executablePath`, `args`, and `ignoreDefaultArgs`. An attacker can therefore cause the probe to spawn an arbitrary executable. Even if Playwright later errors because the spawned process is not a real browser, the command has already executed.

This same execution path is also used for normal scheduled monitors, not only one-shot monitor tests:

-   [https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Jobs/Monitor/FetchList.ts#L110-L121](https://github.com/OneUptime/oneuptime/blob/8e90f451426b160718bdd1796b68c5ec15318101/Probe/Jobs/Monitor/FetchList.ts#L110-L121)

As a result, the issue can be abused either as a one-shot RCE via `Test Monitor` or as a persistent scheduled RCE by saving a malicious Synthetic Monitor.

#### PoC

1.  Log in as any user with normal project membership.
2.  Go to `Monitors -> Create New Monitor`.
3.  Select `Synthetic Monitor`.
4.  In `Playwright Code`, paste the following script:

```
 const HostFunction =
    Object.getOwnPropertyDescriptor(console, "log").value.constructor;

  return {
    data: {
      node: HostFunction('return process.version')(),
      cwd: HostFunction('return process.cwd()')(),
      id: HostFunction(
        'return process.getBuiltinModule("child_process").execSync("id").toString()'
      )(),
    },
  };

```

1.  Select any one browser type, for example `Chromium`.
2.  Select any one screen type, for example `Desktop`.
3.  Set retry count to `0`.
4.  Click `Test Monitor` and choose a probe.

Expected result:

-   the monitor execution succeeded and in the `Show More Details` the command output is shown. <img width="899" height="249" alt="image" src="https://github.com/user-attachments/assets/98ebd26f-431b-438e-9459-7deeebf97b18" />

#### Impact

This is a server-side `Remote Code Execution` issue affecting the probe component.

Who is impacted:

-   any OneUptime deployment where an attacker can obtain ordinary project membership
-   environments where the probe has access to internal services, secrets, Kubernetes metadata, database credentials, proxy credentials, or other cluster-local trust relationships

## Affected Packages

1 total 1 fixed

Ecosystem

Package

Vulnerable range

Fix

📦npm

`@oneuptime/common` 

all versions

10.0.20`npm install @oneuptime/common@10.0.20`

## Affected Products

1 product · 1 configurations

Application

`oneuptime`hackerbay

< 10.0.20

range

## Detection & mitigation playbook

Open-source dependency

1.  ### Detect
    
    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for @oneuptime/common, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
    
2.  ### Fix
    
    Update @oneuptime/common to 10.0.20 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-30921 is resolved across your whole dependency graph.
    
3.  ### Workarounds
    
    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
    

## Frequently Asked Questions

Summary OneUptime Synthetic Monitors allow low-privileged project users to submit custom Playwright code that is executed on the \`oneuptime-probe\` service. In the current implementation, this untrusted code is run inside Node's \`vm\` and is given live host Playwright objects such as \`browser\` and \`page\`. This creates a distinct server-side RCE primitive: the attacker does not need the classic \`this.constructor.constructor(...)\` sandbox escape. Instead, the attacker can directly use the injected Playwright \`browser\` object to reach \`browser.browserType().launch(...)\` and spawn an arbitrary exe

O3 Security · Impact-Aware SCA

### Is CVE-2026-30921 in your dependencies?

Find it across npm, including transitive dependencies.

[Scan my dependencies](/book-demo) [How O3 SCA works](/impact-aware-sca)