Skip to main content

QuickJS CVE-2025-62491

HIGH
Use After Free (CWE-416)
2025-10-16 cve-coordination@google.com
8.8
CVSS 4.0 · Vendor: google
View

Attack ChainAIDerived

Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain

  1. Access
    Supply malicious JS to QuickJS engine
  2. Delivery
    Create promise rejected with Error having getter on reason
  3. Exploit
    Rejection reporter iterates list and invokes getter
  4. Execution
    Getter calls catch() freeing current list entry
  5. Persist
    Loop dereferences freed pointer (UAF)
  6. Impact
    Corrupt heap for code execution

Vulnerability Assessment

Weakness
CWE
ASVS 5.0
V15 - Secure Coding and Architecture Memory lifecycle management
MITRE ATT&CK

2 techniques across 2 tactics: Execution, Privilege Escalation

The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up.

Exploitation Conditions

Exploitation requires that the QuickJS std library's unhandled-rejection reporting path (js_std_promise_rejection_check / js_std_dump_error1, part of quickjs-libc, as used by the qjs interpreter) is active, and that the attacker can execute JavaScript in the engine. The concrete trigger is an unhandled promise rejected with an Error object carrying a custom property getter (defined via Object.defineProperty) that, when invoked during error dumping, calls catch() on the same promise. The primary limiting factor is that the host application must evaluate untrusted/attacker-controlled JavaScript and must use the std library's rejection-tracking (this does not affect pure libquickjs embeddings that do not wire up js_std_promise_rejection_tracker); reliable UAF-to-code-execution also depends on heap grooming, making exploitation non-trivial.

Impact

This is a memory-safety flaw (CWE-416 Use-After-Free) in QuickJS's standard library (quickjs-libc), triggered when the unhandled-rejected-promise reporter iterates ts->rejected_promise_list and a malicious custom getter on an Error object calls catch() on the same promise, freeing the list entry still being iterated. Exploitation fundamentally requires the attacker to supply/execute JavaScript inside the QuickJS engine, so real-world risk is dominated by deployment context: it is high where an application evaluates untrusted/attacker-supplied scripts via the std library, and effectively low where only trusted local scripts run. Signals are mixed: a POC/exploit reference exists (Google issue tracker, tagged 'exploit'), the reporter is Google's CVE coordination team, and the input CVSS 4.0 base is 8.8 (High) - but there is NO CISA KEV listing and NO EPSS score provided, so there is no evidence of active or widespread exploitation. Note a conflict in the input CVSS 4.0 vector: it declares AV:A (adjacent-network), UI:P (passive user interaction) and a scope change (SC:H/SI:H), none of which the description supports - the description describes a local, attacker-controlled-script UAF with no network or remote-user element, so the provided vector appears mis-scored and should be treated with caution. No EPSS and no KEV means prioritization should rest on whether your deployment runs untrusted JS, not on the raw 8.8.

Exploit ScenarioDerived

An application embeds QuickJS and evaluates attacker-supplied JavaScript (e.g., a scripting sandbox, serverless JS runtime, or qjs processing an untrusted script). The attacker creates a promise that rejects with an Error whose 'reason' property has a custom getter defined via Object.defineProperty; when the engine's unhandled-rejection reporter dumps the error, the getter runs and calls catch() on that same promise, freeing the list entry mid-iteration and producing a UAF that can corrupt memory and potentially lead to arbitrary code execution in the host process. A public exploit/POC is referenced in the Google issue tracker.

This Week Schedule remediation this week. Why: HIGH severity (CVSS 7.0-8.9).
No patch listed yet 0.4% exploitation probability (EPSS)

Get an e-mail when this CVE is exploited, patched or re-scored. Free account.

Alert me

AnalysisAIv1 – Oct 19, 2026

A use-after-free in QuickJS's quickjs-libc standard library lets JavaScript code corrupt heap memory from inside the interpreter's own unhandled-promise reporter: when a rejected promise's reason is an Error carrying a JavaScript-defined property getter, dumping that error re-enters the script engine and a catch() call frees the promise entry that the reporter is still iterating. Per the authoritative assessment this is a local, high-complexity memory-safety issue (CVSS 3.1 AV:L/AC:H, high confidentiality and integrity impact) that requires the host to evaluate attacker-controlled JavaScript using the qjs interpreter's rejection-tracking helpers; bare libquickjs embeddings that do not register the rejection tracker are unaffected. Publicly available exploit code exists, though turning the UAF into reliable code execution additionally depends on heap grooming and makes exploitation non-trivial.

RemediationAI

The primary fix is to move to an upstream QuickJS snapshot that contains the corrected rejection reporting - check https://bellard.org/quickjs/Changelog for the entry addressing the rejected_promise_list reentrancy and rebuild quickjs-libc from that source; no exact patched version number is published in the available data, so verify the fix by re-running the reproducer at https://issuetracker.google.com/434195203 against your build. If immediate upgrade is impossible, the most effective compensating control is to not register the std rejection tracker at all: skip js_std_add_helpers/js_std_init_handlers in your embedding and handle 'unhandledRejection'-style reporting in application code that snapshots the promise list into a separate array before formatting any reason (trade-off: you lose qjs's built-in rejection diagnostics and the default global helpers installed by those calls). Where the qjs interpreter must stay in use, never feed it untrusted or attacker-controlled JavaScript, or sandbox it in a separate low-privilege process with restricted memory and no host-object bridges (trade-off: reduced functionality and added sandboxing overhead, and a crash inside the sandbox remains a denial-of-service vector). A code-level hardening alternative is to defer freeing JSRejectedPromiseEntry objects that are being iterated (or to re-check list membership before advancing el), which keeps diagnostics intact but requires maintaining a local patch against quickjs-libc. Keep heap-exploitation mitigations enabled (ASLR, hardened allocators, stack canaries) while any interim mitigation is in place, since the underlying primitive is heap corruption.

Affects your stack

Find out whether the stacks and servers you run are on an affected version.

Checking this CVE against your own stacks and servers is part of the Basic plan and up.

Technical ContextAI · show details

QuickJS is Fabrice Bellard's small embeddable JavaScript engine; the vulnerable code lives in quickjs-libc (the std library used by the bundled qjs interpreter), not in the engine core. js_std_promise_rejection_check walks the per-runtime linked list ts->rejected_promise_list with a conventional el = el->next loop, and for each entry calls js_std_dump_error1(ctx, rp->reason) to report the rejection. Because the rejection reason is an ordinary JS Error object, any property getter installed on it with Object.defineProperty (for example on message, stack, or a custom field touched during formatting) is re-entered while the dump is in progress. If that getter calls catch() on the very promise being reported, js_std_promise_rejection_tracker fires, removes and frees the corresponding JSRejectedPromiseEntry, and the outer loop then dereferences and advances through freed memory - classic CWE-416 use-after-free caused by reentrancy into code that invalidates an iteration-in-progress data structure. Consequences range from interpreter crash and information disclosure to heap corruption with the potential for code execution, depending on allocator behaviour and object reuse. The CPE cpe:2.3:a:quickjs_project:quickjs:*:*:*:*:*:*:*:* reflects that no version constraint is published, so every QuickJS snapshot shipping this reporting path should be treated as in scope until the upstream changelog entry is confirmed applied.

Know when Quickjs gets its next vulnerability

  • Watch products and get an email when something new is published
  • Check this CVE against your own stack and servers
  • Exploit and PoC references, threat intelligence from 22 sources

No credit card · 7-day full trial

Severity by source

Vendor (google) PRIMARY 8.8 HIGH
CVSS:4.0/AV:A/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:L/SC:H/SI:H/SA:L
vuln.today AI 7.4 HIGH

Attacker must supply JavaScript to the local engine (AV:L), the getter-driven UAF race is precise and hard to weaponize reliably (AC:H), no authentication to the engine is needed (PR:N), and successful memory corruption yields full process compromise (C/I/A:H).

3.1 AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
4.0 AV:L/AC:H/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Primary rating from Vendor (google).

CVSS VectorVendor: google

Attack Vector
Adjacent
Attack Complexity
High
Attack Requirements
Present
Privileges Required
None
User Interaction
Passive
Vulnerable system: Confidentiality
High
Vulnerable system: Integrity
High
Vulnerable system: Availability
Low
Subsequent system: Confidentiality
High
Subsequent system: Integrity
High
Subsequent system: Availability
Low

DescriptionCVE.org

A Use-After-Free (UAF) vulnerability exists in the QuickJS engine's standard library when iterating over the global list of unhandled rejected promises (ts->rejected_promise_list).

  • The function js_std_promise_rejection_check attempts to iterate over the rejected_promise_list to report unhandled rejections using a standard list loop.
  • The reason for a promise rejection is processed inside the loop, including calling js_std_dump_error1(ctx, rp->reason).
  • If the promise rejection reason is an Error object that defines a custom property getter (e.g., via Object.defineProperty), this getter is executed during the error dumping process.
  • The malicious custom getter can execute JavaScript code that calls catch() on the same rejected promise being processed.
  • Calling catch() internally triggers js_std_promise_rejection_tracker, which then removes and frees the current promise entry (JSRejectedPromiseEntry) from the rejected_promise_list.
  • Since the list iteration continues using the now-freed memory pointer (el), the subsequent loop access results in a Use-After-Free condition.

Executive ViewAI

Why It Matters

QuickJS's quickjs-libc library contains a memory-safety flaw that can let attacker-supplied JavaScript corrupt heap memory in hosts that use the qjs interpreter's unhandled-promise rejection-tracking path. This matters to leadership wherever QuickJS is embedded in products, sandboxes, or services that process untrusted scripts, because successful exploitation could undermine confidentiality and integrity, though the attack is local, high-complexity, and publicly available exploit code exists.

Business Impact: High
Compensating Controls

No vendor-released patch identified at time of analysis; disable or avoid qjs unhandled-promise rejection tracking when evaluating untrusted JavaScript, run qjs in a hardened sandbox with least privilege, restrict script input to trusted sources, and monitor for crashes or memory-corruption indicators.

Threat Intelligence Overview

EPSS Score
0.4%
Top 66% exploitable
Prevalence
Medium
popular lightweight embeddable JS engine, moderate but not universal deployment
Exploit
POC
Public exploit code exists
Data Quality
2 sources
Confidence: Low

How this decision was reached

The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.

SignalValue
Severity HIGH
CISA KEV No
Public POC Yes
EPSS 0.4%
Patch available No
Active threat No
Deciding rule
HIGH severity (CVSS 7.0-8.9)
What every action level means
Emergency Immediate action required. Criteria: CRITICAL + in CISA KEV (actively exploited) without patch, OR CRITICAL + EPSS > 30% without patch, OR CRITICAL + active threat signals without patch.
Act Now Prioritize within 24-48h. Criteria: in KEV with patch available, OR CRITICAL + public POC, OR HIGH + EPSS > 10%, OR CRITICAL + active threat, OR any CRITICAL severity.
This Week Schedule remediation this week. Criteria: HIGH severity (CVSS 7.0-8.9). Patch within normal change window.
This Month Plan within 30 days. Criteria: MEDIUM severity (CVSS 4.0-6.9), lower exploitation probability. Include in regular patch cycle.
Monitor Track and reassess. Criteria: LOW severity (CVSS 0.1-3.9), minimal exploitation risk. No immediate action needed.

SSVC AssessmentENISA

SSVC Decision· derived
Scheduled
Exploitation· derived
Poc
System Exposure· derived
Controlled
Automatable· derived
No
Human Impact
High

Priority Score

64
Low Medium High Critical
KEV: 0
EPSS: 0
CVSS: +44
PoC: +20
Weaponized: 0
Threat intel: 0
Gov advisory: 0

Attack Technique

Use-after-free vulnerabilities occur when a program continues to access memory through a pointer after that memory has been deallocated.

Memory corruption occurs when a program writes data beyond the boundaries of allocated memory regions or accesses memory in unintended ways, violating the integrity of the process's address space.

Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.

Affected Products (CPE)CVE.org

cpe:2.3:a:quickjs_project:quickjs:*:*:*:*:*:*:*:*
CVE-2025-62490 HIGH POC
8.8 Oct 16

Use-after-free in QuickJS object-printing routines can corrupt memory when an attacker-influenced Array, Map, or Set is

CVE-2023-31922 HIGH POC
7.5 May 12

QuickJS commit 2788d71 was discovered to contain a stack-overflow via the component js_proxy_isArray at quickjs.c. Rated

CVE-2025-62496 HIGH POC
7.1 Oct 16

Heap out-of-bounds write in QuickJS's BigInt string parser can corrupt memory when an embedding application converts an

CVE-2025-62495 HIGH POC
7.1 Oct 16

Integer overflow in QuickJS's libregexp bytecode accounting can become an out-of-bounds write when a crafted recursive r

CVE-2025-62494 HIGH POC
7.1 Oct 16

Type confusion in QuickJS's handling of the string addition (+) operation allows local attackers to trigger out-of-bound

CVE-2025-62492 MEDIUM POC
5.9 Oct 16

Information disclosure in QuickJS occurs through a floating-point precision error in TypedArray.prototype.indexOf() when

CVE-2025-62493 MEDIUM POC
5.9 Oct 16

An out-of-bounds heap read in QuickJS's BigInt-to-string conversion (js_bigint_to_string1) lets script-controlled BigInt

CVE-2026-88378 CRITICAL
9.8 Sep 24

Heap out-of-bounds write in QuickJS's bytecode deserializer (JS_ReadFunctionTag) lets a crafted serialized blob corrupt

CVE-2025-46687 MEDIUM POC
5.6 Apr 27

quickjs-ng through 0.9.0 has a missing length check in JS_ReadString for a string, leading to a heap-based buffer overfl

CVE-2025-46688 MEDIUM POC
5.6 Apr 27

quickjs-ng through 0.9.0 has an incorrect size calculation in JS_ReadBigInt for a BigInt, leading to a heap-based buffer

CVE-2026-0821 MEDIUM POC
5.5 Jan 10

Heap-based buffer overflow in QuickJS up to version 0.11.0 within the js_typed_array_constructor function allows unauthe

CVE-2024-13903 MEDIUM POC
5.3 Mar 21

A vulnerability was found in quickjs-ng QuickJS up to 0.8.0. Rated medium severity (CVSS 5.3), this vulnerability is rem

References

Advisories & patches

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy