CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-23830

Async Abyss: Escaping SandboxJS via Forgotten Constructors

Alon Barad
Alon Barad
Software Engineer

Jan 27, 2026·5 min read·76 visits

Executive Summary (TL;DR)

SandboxJS locked the front door (`Function`) but left the side door (`AsyncFunction`) wide open. By accessing the constructor of an async arrow function, attackers can instantiate code that executes in the host's context, not the sandbox, achieving instant Remote Code Execution (RCE).

A critical oversight in SandboxJS allowed attackers to bypass the execution environment completely by leveraging the AsyncFunction constructor. While the standard Function constructor was proxied, its asynchronous sibling was left unguarded.

The Hook: Building Prisons with Duct Tape

JavaScript sandboxing is effectively an arms race between library maintainers and the ECMAScript specification. The goal of SandboxJS is simple: take untrusted code, parse it, identify the scary bits, and execute it in a padded cell where it can't touch process, require, or your AWS keys.

To achieve this, SandboxJS doesn't just run code; it dissects it. It creates an execution context that mimics the global scope but replaces dangerous natives with shimmed, safe versions. You call eval()? You get a safe eval. You call Function()? You get a safe function factory.

But here's the problem with JavaScript: there is never just one way to do anything. While the developers were busy barricading the standard Function constructor, they forgot that ECMAScript 2017 introduced a trendy new sibling: AsyncFunction. This oversight turns the entire sandbox into a suggestion rather than a rule.

The Flaw: The Invisible Constructor

The root cause of CVE-2026-23830 is a classic "allowlist miss." The library maintains a WeakMap called evals that maps native constructors to their sandboxed counterparts. When the sandbox encounters code trying to create a new function, it checks this map. If it sees the Function constructor, it redirects the call to a safe implementation.

However, the AsyncFunction constructor is not a global object you can just type into the console (like Array or Date). It is hidden. It effectively doesn't exist in the global namespace.

Because it wasn't sitting out in the open, the developers seemingly forgot it existed. They didn't add it to the evals map. This meant that if an attacker could get a reference to it, the sandbox would look at it, shrug, and say, "I don't have a rule for this, so here is the real, native host object." And just like that, the prisoner is given the keys to the warden's office.

The Code: The Smoking Gun

Let's look at src/utils.ts before the patch. The code is explicitly setting up protections for specific dangerous globals. It's almost tragic to see Function and eval being handled so carefully right next to the gaping hole.

// BEFORE FIX
if (evalContext) {
  const func = evalContext.sandboxFunction(execContext);
  evals.set(Function, func);
  // <--- The silence here is deafening.
  evals.set(eval, evalContext.sandboxedEval(func));
}

The fix involves acknowledging that AsyncFunction exists. Since it's not globally accessible by name, the patch has to perform a bit of prototype gymnastics to capture it:

// AFTER FIX (src/utils.ts)
 
// 1. Capture the elusive constructor
export const AsyncFunction: Function = Object.getPrototypeOf(async function () {}).constructor;
 
// 2. Map it to a safe version
if (evalContext) {
  const func = evalContext.sandboxFunction(execContext);
  const asyncFunc = evalContext.sandboxAsyncFunction(execContext);
  
  evals.set(Function, func);
  evals.set(AsyncFunction, asyncFunc); // <--- The door is now locked.
  evals.set(eval, evalContext.sandboxedEval(func));
}

This highlights a fundamental fragility in JS sandboxes: you have to know every possible way to generate code to stop code generation.

The Exploit: Walking the Prototype Chain

So, how do we weaponize this? We can't just type new AsyncFunction(...) because AsyncFunction isn't a global variable. But we can derive it. Every async function is an instance of AsyncFunction. By defining a throwaway async arrow function and checking its .constructor property, we get a handle on the Native Host Constructor.

Here is the step-by-step kill chain:

  1. Derive the Constructor: Create a harmless async function inside the sandbox.
  2. Steal the Reference: Access its .constructor property. Because the sandbox doesn't recognize this object in its evals map, it hands you the real host constructor.
  3. Payload Delivery: Use that constructor to build a new function containing malicious code.
  4. Execute: Run the function. It executes in the host scope, bypassing the sandbox entirely.
// The PoC - One Line of Doom
const hostProcess = await (async () => {}).constructor("return process")();
 
// Taking it further (RCE)
const rce = (async () => {}).constructor(
  "return process.mainModule.require('child_process').execSync('id').toString()"
);
 
console.log(await rce());
// Output: uid=0(root) gid=0(root) ...

This is elegant in its simplicity. No memory corruption, no race conditions, just asking JavaScript for a feature it happily provides.

The Impact: Game Over

The impact here is maximum severity. If you are using SandboxJS to run user-submitted scripts—perhaps for a plugin system, a rules engine, or a 'code playground'—you are compromised.

Because the code generated by AsyncFunction runs in the host context (the global scope where the Node.js process lives), the attacker has access to everything the host process has access to:

  • Environment Variables: AWS keys, database credentials (process.env).
  • File System: Reading SSH keys, writing backdoors (fs module via require).
  • Network: Launching reverse shells or pivoting to internal networks.

This isn't just a data leak; it is full remote server control. The CVSS score of 9.8 is well-deserved.

The Fix: Patching and Lessons Learned

The immediate fix is to upgrade SandboxJS to the version containing commit 345aee6. If you cannot upgrade, you are theoretically out of luck, as monkey-patching the library externally is difficult due to how it initializes its context maps.

For Developers & Researchers: This vulnerability serves as a reminder that Function is not the only way to generate code. When auditing sandboxes, always check for the "exotic" constructors:

  • AsyncFunction: (async()=>{}).constructor
  • GeneratorFunction: (function*(){}).constructor
  • AsyncGeneratorFunction: (async function*(){}).constructor

If the sandbox blocks Function but misses any of the above, it's game over. Defense in depth suggests that relying solely on a JS-based sandbox for high-risk code execution is inherently risky. Consider using actual isolation technologies like WebAssembly, Firecracker microVMs, or Deno sub-processes for true security.

Official Patches

nyarivCommit fixing the AsyncFunction leak

Fix Analysis (1)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Systems

Node.js applications using nyariv/SandboxJSSaaS platforms allowing user-defined scripts via SandboxJSRule engines executing dynamic JS logic

Affected Versions Detail

Product
Affected Versions
Fixed Version
SandboxJS
nyariv
< Commit 345aee6Commit 345aee6
AttributeDetail
CWE IDCWE-94 (Code Injection)
CVSS v3.19.8 (Critical)
Attack VectorNetwork
ImpactFull Sandbox Escape / RCE
Exploit StatusPoC Available
Affected Componentevals WeakMap / AsyncFunction Constructor

MITRE ATT&CK Mapping

T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1211Exploitation for Defense Evasion
Defense Evasion
CWE-94
Code Injection

Improper Control of Generation of Code ('Code Injection')

Known Exploits & Detection

Internal ResearchPoC involves accessing (async()=>{}).constructor to generate code outside the sandbox.

Vulnerability Timeline

Patch Authored and Merged
2026-01-16
Advisory GHSA-wxhw-j4hc-fmq6 Published
2026-01-27

References & Sources

  • [1]SandboxJS Repository
  • [2]GitHub Advisory

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•CVE-2026-105749
6.5

CVE-2026-105749: Unbounded Table Attributes in Docling Backends Leads to Resource Exhaustion

An uncontrolled resource consumption vulnerability exists in the Docling document conversion library. Maliciously structured HTML, JATS, ODS, or BoxNote inputs containing table cells with excessively large 'rowspan' or 'colspan' attribute values trigger algorithmic complexity conditions. This allows unauthenticated remote attackers to initiate resource exhaustion states, crashing or hanging the target document processing pipeline while bypassing configured timeouts.

Amit Schendel
Amit Schendel
2 views•6 min read
•about 1 hour ago•CVE-2026-105748
4.3

CVE-2026-105748: Local File Inclusion and Arbitrary File Disclosure in Docling Document Parser

A Local File Inclusion (LFI) and Arbitrary File Disclosure vulnerability exists in Docling and Docling Slim versions >= 2.16.0 up to 2.131.0. When parsing serialized DoclingDocument structures using the JSON input format, the backend fails to restrict image URI schemes, allowing remote attackers to retrieve local files and verify path existence on the host system during embedded document export.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 2 hours ago•CVE-2026-105744
7.5

CVE-2026-105744: Arbitrary File Read and Remote Code Execution in Docling Tectonic Engine

Docling, a tool for parsing and processing diverse document formats, is vulnerable to arbitrary file read, arbitrary file write, and potential remote code execution (RCE) in versions 2.94.0 through 2.131.0. The vulnerability occurs when applications configure Docling to use the Tectonic engine for rendering TikZ diagrams into images. Because the compilation did not restrict hazardous TeX primitives or sandbox the environment, an attacker can supply crafted documents containing malicious TikZ definitions to access or modify local files and execute arbitrary commands under the privileges of the processing application.

Amit Schendel
Amit Schendel
7 views•7 min read
•about 4 hours ago•CVE-2026-105743
4.0

CVE-2026-105743: Server-Side Request Forgery Guard Bypass in Docling Document Conversion Engine

An SSRF guard bypass vulnerability in the Docling document conversion engine allows unauthenticated attackers to bypass internal IP access controls. The vulnerability exists due to a DNS rebinding Time-of-Check Time-of-Use (TOCTOU) condition, URL authority parsing inconsistencies, and unvalidated network requests triggered during headless browser page rendering.

Amit Schendel
Amit Schendel
6 views•6 min read
•about 4 hours ago•CVE-2026-105742
3.7

CVE-2026-105742: Sensitive Custom Header Leakage in Docling Image Resource Loader

A technical analysis of CVE-2026-105742 (GHSA-p3fw-7699-7926), a sensitive information disclosure vulnerability in the Docling document processing library. Vulnerable versions of Docling indiscriminately forward custom HTTP headers, such as authentication tokens, to arbitrary third-party origins and during cross-origin redirects while fetching remote image assets from untrusted HTML and EPUB documents.

Alon Barad
Alon Barad
6 views•6 min read
•about 6 hours ago•CVE-2026-106121
4.9

CVE-2026-106121: Denial of Service via Infinite Loop in RabbitMQ Java Client JSON Parser

CVE-2026-106121 is a Denial of Service (DoS) vulnerability in the RabbitMQ Java Client library (amqp-client) affecting versions prior to 5.37.0. The vulnerability resides in the legacy, custom JSON-RPC parsing class com.rabbitmq.tools.json.JSONReader. When parsing malformed or truncated payloads ending within a quoted string or single-line comment, the parser's scanner enters an infinite loop. This occurs because the loop lacks an exit condition for the end-of-input sentinel character returned by the iterator, leading to either CPU exhaustion or a JVM crash from an OutOfMemoryError.

Amit Schendel
Amit Schendel
8 views•6 min read