CVE-2026-85046 and Northstar browser
Verdict: Northstar is not vulnerable to CVE-2026-85046. The bug is a type confusion inside V8’s optimizing JIT compilers. Northstar does not contain V8, does not contain any JIT compiler, and its JavaScript engine has no equivalent of the data structure the bug corrupts. The vulnerable code, the vulnerable representation and the exploitation primitive are all absent from this codebase.
This article records what the vulnerability is, why it cannot apply to Northstar, the GPL-licensed single-process edition of the Nordstjernen engine, and how to verify the claims against the source tree. The same reasoning holds for Nordstjernen itself, which runs the same quickjs-ng interpreter and carries no JIT either.
« About the Northstar Browser · Back to nordstjernen.org · This document in the repository
the vulnerability
| identifier | CVE-2026-85046 |
|---|---|
| component | V8, the JavaScript and WebAssembly engine in Chromium |
| weakness | CWE-843, access of resource using incompatible type (type confusion) |
| severity | High, CVSS 8.8 |
| affected | Google Chrome before 152.0.7977.82, and every Chromium-derived browser that ships the same V8 (Edge, Brave, Opera, Vivaldi, Electron-based applications) until they rebase |
| reported | 4 August 2026 by Salvatore Gulizia (Serotav) |
| fixed | 3 September 2026 in Chrome 152.0.7977.82 (Linux) and 152.0.7977.82/.83 (Windows, macOS) |
| exploited | Yes. Google confirmed an in-the-wild exploit; CISA added it to the Known Exploited Vulnerabilities catalogue on 4 September 2026 with an 18 September 2026 remediation deadline. It is the sixth Chrome zero-day of 2026. |
The published description is “type confusion in V8 in Google Chrome prior to 152.0.7977.82 allowed a remote attacker to execute arbitrary code inside the sandbox via a crafted HTML page.” No privileges are required; the victim only has to load attacker-controlled content.
Mechanism
V8 gives every JavaScript array an elements kind, recorded in the object’s hidden-class map. PACKED_SMI_ELEMENTS promises that every slot holds a small integer encoded directly in the word; PACKED_ELEMENTS means slots may hold tagged pointers to heap objects. The optimizing compilers, Maglev and TurboFan, speculate on the elements kind so that they can emit unchecked loads and stores and skip the garbage collector’s write barrier for arrays that hold no pointers.
The bug lives in the compilers’ reduction of Array.prototype.sort (maglev-graph-builder.cc, TryReduceArrayPrototypeSort, with the same logic in TurboFan). When the graph builder can prove the receiver is a plain array, it replaces the call with an inlined insertion sort: check the receiver’s maps, copy the elements out, sort the copy while calling the page-supplied comparator, re-check maps and length, and copy the result back. The comparator runs arbitrary page script between the two checks, and the re-check did not account for the transition it can provoke, so an array whose storage holds heap pointers ends up carrying a map that declares it holds only small integers.
From there every later operation trusts the wrong map. Moving a tagged pointer as though it were an integer skips the write barrier, which gives the attacker a stale reference the garbage collector does not know about, and that is turned into arbitrary read and write on the V8 heap and then code execution inside the renderer sandbox.
Every step of that chain depends on V8-specific machinery: a per-array elements kind, hidden-class maps, speculative optimizing compilers that inline builtins, deoptimization checks, and a generational garbage collector with write barriers.
why Northstar is not affected
There is no V8
Northstar carries no upstream browser engine. JavaScript runs on quickjs-ng, consumed as a meson subproject pinned to the v0.16.2 release (subprojects/quickjs-ng.wrap) with no in-tree fork. None of the files, classes or builtins named in the advisory exist in this tree. There is no v8/ directory, no maglev-graph-builder.cc, no TurboFan, no Sparkplug, no Ignition, and no Chromium source of any kind.
There is no JIT compiler of any kind
CVE-2026-85046 is a bug in code that generates machine code from speculative assumptions about JavaScript values. Northstar has no such code path:
- quickjs-ng is a bytecode interpreter. It compiles source to bytecode once and executes it with a switch loop. It performs no type speculation, has no optimizing tier, no inline caches keyed on object shape, no on-stack replacement and no deoptimization. Builtins such as
Array.prototype.sortare ordinary C functions that are called, never inlined into generated code. - WebAssembly is interpreted too. It runs on a vendored subset of WAMR built as the classic interpreter only (
src/wamr/meson.build:WASM_ENABLE_INTERP=1,WASM_ENABLE_FAST_INTERP=0, no AOT and no JIT sources compiled). - W^X holds for the whole process. The build links nothing that maps writable-and-executable memory, and on Windows the process opts into
ProcessDynamicCodePolicy, so a request forPAGE_EXECUTE_*memory is refused by the kernel.
A speculation-and-bailout bug cannot exist in an engine that never speculates.
There is no elements kind to confuse
The corrupted datum in CVE-2026-85046 is a per-array summary of what the slots contain, stored separately from the slots. QuickJS has no such summary. Every JSValue carries its own tag (JS_TAG_INT, JS_TAG_OBJECT, JS_TAG_STRING, and so on) next to its payload, and a fast array is simply a contiguous vector of those tagged values. Reading an element means reading the element’s own tag; there is no map that can say “integer” while the slot holds a pointer. The property the exploit desynchronises does not exist, so it cannot be desynchronised.
There is no write barrier to skip
The exploit turns the confusion into a primitive by making V8 omit a generational garbage collector’s write barrier. QuickJS manages memory by reference counting with a cycle collector for leaked cycles. There is no generational heap, no remembered set and no write barrier, so the primitive the attacker builds on has no counterpart in Northstar.
Array.prototype.sort is written defensively
The quickjs-ng implementation (js_array_sort in quickjs.c) is straightforward and generic:
- Read the length and copy every element out through the normal property-get path (
JS_TryGetPropertyInt64), each copy holding its own reference. - Sort the private copy with
rqsort, calling the comparator throughJS_Call. The comparator may do anything to the original array; the sort never touches the array while it runs. - Write the result back through
JS_SetPropertyInt64, one element at a time. Every store goes through the same checks any script store would, against the array as it is at that moment, including its current length and whether it is still a fast array at all.
A comparator that mutates, shrinks, freezes or reshapes the receiver mid-sort therefore changes nothing about how the write-back is validated. This is exactly the property the inlined V8 fast path lost.
Defence in depth around the engine
Northstar is the single-process edition: there is no renderer sandbox in the Chromium sense, and a memory-safety bug in the engine would not be contained between pages. That is why the absence of this bug class matters more here than it would behind a process boundary, and why the hardening around the engine is chosen to deny the follow-on steps an exploit of this shape needs:
- Compile-time hardening. PIE, full RELRO, non-executable stack,
-fstack-protector-strong,-fstack-clash-protection,-fcf-protection=full,_FORTIFY_SOURCE=3. - Platform sandboxes. On Linux, a seccomp allow-list and a Landlock filesystem ruleset are installed at startup (
src/security.c); on macOS the platform sandbox; on Windows the process-mitigation policies includingDisableDynamicCode. - A bounded runtime. The QuickJS runtime is created with a memory limit and a stack limit (
src/js.c), and is torn down on every cross-origin navigation.
related hardening in this tree
The advisory is a reminder of a general shape: a native fast path validates an object, runs page script, and then trusts the earlier validation. Northstar’s own DOM and Web API bindings are C code over QuickJS, so the same shape could in principle appear there even though the JIT bug cannot. Release 1.0.8 audited the bindings for it and fixed the places that held a raw pointer into a page-owned ArrayBuffer across a property read whose getter can run page script: putImageData, AnalyserNode.getByteTimeDomainData and getByteFrequencyData, and the offline AudioBufferSourceNode renderer (src/js_canvas.c, src/js.c, src/webaudio.c). Each now reads every page-visible property first and fetches the backing bytes as the last step, so the bounds and detached checks see the buffer as it is when the bytes are used. That work is a different bug class (a stale backing-store pointer, not a type confusion), but it closes the same “script ran in the middle” window at the boundary Northstar does own.
how to verify
Run these from the root of a northstar-browser checkout.
# No V8, no Chromium, no Maglev/TurboFan sources anywhere in the tree.
grep -rIl --exclude-dir=.git --exclude-dir=docs -i "maglev\|turbofan\|PACKED_SMI_ELEMENTS" . ; echo "(no output above means none)"
ls v8 third_party/v8 2>/dev/null ; echo "(no such directories)"
# The JavaScript engine is pinned quickjs-ng, an interpreter.
cat subprojects/quickjs-ng.wrap
# WebAssembly is the WAMR classic interpreter; no AOT or JIT is compiled.
grep -n "WASM_ENABLE" src/wamr/meson.build
grep -c "aot\|jit" src/wamr/meson.build
# The QuickJS sort copies out, sorts privately, and stores back through
# the checked property path (after `meson setup builddir` has fetched it).
grep -n "js_array_sort\|JS_TryGetPropertyInt64\|JS_SetPropertyInt64" \
subprojects/quickjs-ng/quickjs.c | sed -n 1,12p
references
- NVD: CVE-2026-85046
- CISA Known Exploited Vulnerabilities catalogue
- Researcher write-up, Salvatore Gulizia: “When Sorting Leads To Confusion”
- Chrome Releases, stable channel update for desktop, 3 September 2026
- Help Net Security: “Google patches actively exploited Chrome zero-day (CVE-2026-85046)”
- Security Affairs: “Google fixes the sixth actively exploited Chrome zero-day of 2026”
- The Hacker News: “Google Releases Chrome Update to Patch Actively Exploited V8 Zero-Day”
- BleepingComputer: “Google warns of new Chrome zero-day flaw exploited in attacks”
- Northstar: SECURITY.md (threat model, sandbox, JavaScript section), docs/architecture.md (process model), docs/cve-2026-85046.md (this analysis in the repository)
