Skip to content

Product1 publisher3 min readPublished

V8's ToBoolean path leaks the secret bit that constant-time-js was written to hide

A University of British Columbia team showed that three selection functions in Soatok's constant-time-js leak their condition through V8's cache behaviour. He shipped version 0.5.0 and requested a CVE.

The Product Desk · Product desk

Illustration accompanying V8's ToBoolean path leaks the secret bit that constant-time-js was written to hide

What happened

  • Soatok was at a furry convention last month when a Ph.D student named Yayu Wang emailed him a side-channel disclosure against his demonstration library constant-time-js.
  • The report says select, select_alt and select_ints still produce secret-dependent instruction- and data-cache behaviour in V8, so the cache-access pattern can reveal the selection condition.
  • The research behind the finding was done by Yayu Wang, Kjell Dankert, Duy Kha Dinh and Aastha Mehta at the University of British Columbia.
  • Soatok has released version 0.5.0 with a fix and used GitHub's security advisories feature to request a CVE for the issue.

Compiled by The Product DeskSomething wrong?How this is made

Why it matters

  • constraint Branchless source buys nothing when the engine picks the instructions, so a JavaScript selection function cannot promise a same-machine attacker what its name implies.
  • decision Teams doing secret-dependent selection in JavaScript have to pick between relocating that operation to code whose emitted instructions they can inspect and writing the cache-line caveat into their own documented threat model.
  • exposure Since the maintainer cannot see which closed-source builds copied his pattern, an assigned CVE is the only path by which those users find out they are affected.
  • cost Closing the gap between algorithmic constant-time and machine-level constant-time takes formal verification work that an unpaid hobby maintainer says he cannot fund.

A developer who calls `select(condition, a, b)` in a crypto routine is buying one property: the same instructions run and the same memory gets read whichever way the secret bit falls. The disclosure email from the University of British Columbia group, which Soatok reproduced in the pull request for the fix, says the property does not survive the trip from JavaScript to the machine. Yayu Wang wrote that the leakage arises from V8's ToBoolean mechanism, its different handling of -0 and -1, and direct accesses to the raw true and false Oddball objects on different cache lines [8].

There is no `if` in the library's source. V8 still has to decide whether the condition is truthy, and the path it takes to do that touches different cache lines depending on the answer [8]. An attacker measuring cache accesses on the same machine learns the condition.

Soatok documented the limit himself, six years early: his 2020 guide said the algorithms it discussed could not rule out compiler or runtime optimizations that undermine security goals [25], and stated the ceiling plainly: "You can achieve algorithmic constant-time, but any higher assurance was outside the scope of the work being done" [2]. On the cost of doing better, he wrote that "as a furry who writes blog posts in my spare time for fun, I don't exactly have the budget for massive research projects in formal verification" [22].

The email arrived at 4:51 PM on 2026-08-21 and he answered Wang at 4:54 PM, three minutes later [11][18], with "I'm currently traveling and will not be at a keyboard until Tuesday" [12]. Handling was quick where one person controlled it. He verified the report and wrote a patch on 25 August, and sent it to everyone on the thread the next day [13][14], five days after the first email [19]. Wang confirmed the leakage was gone on 9 September, 14 days after receiving the patch [15][21], and version 0.5.0 went public on 10 September, 20 days after disclosure [16][20].

Why verify first? Soatok wrote that AI-driven vulnerability hunting, "punctuated by severity inflation and frequent hallucinations", has significantly increased the proportion of bogus reports to legitimate ones [17].

The measured blast radius is zero. NPM shows no dependent packages for constant-time-js [4], and Soatok said he has no idea whether any proprietary software built on his designs [5]. The CVE request is aimed at those users: he wrote that an `npm audit` result or an assigned CVE is likely to trip a company's internal security processes and prompt an upgrade [10]. The report covers three named functions in one library on one engine, and it does not measure other JavaScript cryptography code.

For anyone weighing a constant-time helper in JavaScript, the question is whether the threat model includes an attacker who can observe cache behaviour on the same host. Then whether you can inspect the instructions your runtime emits for the branchless expression you wrote. In a JIT the second answer is no, and here the engine's own boolean conversion is the leak [8]. Where the first answer is yes, that operation belongs in code whose output you can read, or the function's documentation has to name the attacker it stops short of. The cheap version of that work costs a paragraph. Formal verification is the expensive version, and the library's author said he cannot fund it [22].

What to watch

  • Whether the UBC group reports the same V8 leakage in other JavaScript constant-time helpers or in other engines.
  • Whether the requested CVE is assigned, and whether any closed-source user surfaces after npm audit flags it.
  • Whether V8 maintainers treat the cache-line behaviour of ToBoolean and the Oddball objects as something to change in the engine.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories