Skip to content

Commit 093494c

Browse files
patriksimekclaude
andcommitted
fix(GHSA-248r-7h7q-cr24): close async generator yield*-return thenable exception capture
Wrap %AsyncGeneratorPrototype%.next/.return/.throw to sanitise both iterator-result values/rejections and the thenable arguments V8 awaits in yield*-return abrupt completion. The non-thenable branch of the thenable wrapper always resolves with a sandbox-realm shadow (own descriptors copied except .then) so V8's [[Get]] in PromiseResolveThenableJob cannot re-detect a thenable on the user's value via getter or descriptor TOCTOU. Restores Defense Invariant #2 for the implicit-catch case in V8's async generator state machine. Bumps version to 3.11.3. ATTACKS.md gains Category 29 with the full mitigation rationale and trade-off discussion. CHANGELOG.md updated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7a552e8 commit 093494c

5 files changed

Lines changed: 1462 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## [3.11.3]
4+
5+
Single advisory closed. Patch release — no API changes.
6+
7+
### Security fix
8+
9+
- **GHSA-248r-7h7q-cr24** — async generator `yield*`-return thenable exception capture. Calling `i.return(thenable)` on an async generator delegating to a no-`return` inner iterator let V8's `PromiseResolveThenableJob` capture synchronous throws from the thenable's `.then` and surface them to sandbox code as iterator results — bypassing both the transformer's `catch` instrumentation and the `globalPromise.prototype.then` rejection sanitiser. Two-layer defense on `%AsyncGeneratorPrototype%.next/.return/.throw` in `lib/setup-sandbox.js`: every iterator-result promise routes value and rejection through `handleException`, and every thenable argument is replaced with a sandbox-realm wrapper whose `.then` is a fixed `safeThen` that sanitises sync throws and recursively re-wraps any nested thenable handed to `resolve(...)`. When `safeThen` reads `value.then` and it is non-function, the wrapper always resolves with a `{__proto__: null}` shadow so V8's re-read of `.then` cannot observe attacker-controlled values — closing every counting/self-replacing-getter TOCTOU variant. Trade-off: identity is not preserved for non-thenable values passed to `i.return(x)`. ATTACKS.md Category 29.
10+
311
## [3.11.2]
412

513
Three advisories closed. Patch release — no API changes.

0 commit comments

Comments
 (0)