fix: bounds-check UTF-8 char length in String methods (GHSA-m75h-734r-wc7j) - #459
Merged
Merged
Conversation
GHSA-m75h-734r-wc7j
utf8_charbytes() classifies a UTF-8 sequence from its leading byte alone and
returns a claimed length of 1-4 (0 for a continuation/invalid byte) without
verifying that many bytes remain in the buffer. The String core methods trusted
that length directly, giving two script-reachable bugs:
- Heap OOB read: string iteration (string_iterator_next), String.loop() and
String.raw() copy n bytes from the current index. A valid trailing lead byte
(e.g. 0xF0 -> n=4) with fewer bytes left made VALUE_FROM_STRING memcpy past
the allocation.
- Infinite-loop DoS: String.split("") advances i += utf8_charbytes(...). A
leading continuation byte (0x80) yields n=0, so i never advances and the
result list grows without bound (GC disabled) until the process hangs / OOMs.
Add utf8_charbytes_safe(), which clamps the reported length to the bytes that
remain and never returns less than 1, so every scan both stays in bounds and
makes forward progress. Route all five String call sites through it. A
truncated or invalid sequence now degrades to a single raw byte instead of
reading out of bounds or stalling.
Add a regression test covering the split("") DoS, out-of-bounds iteration and
raw() on a lone truncated lead byte.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the heap out-of-bounds read and the infinite-loop DoS reported in GHSA-m75h-734r-wc7j (CWE-125 / CWE-835).
utf8_charbytes()classifies a UTF-8 sequence from its leading byte alone and returns a claimed length of 1–4 (0 for a continuation/invalid byte) without checking that many bytes actually remain in the buffer. The String core methods trusted that length directly, yielding two script-reachable bugs:string_iterator_next),String.loop()andString.raw()copynbytes from the current index. A valid trailing lead byte (e.g.0xF0→ n=4) with fewer bytes left madeVALUE_FROM_STRINGmemcpypast the allocation.String.split("")advancesi += utf8_charbytes(...). A leading continuation byte (0x80) yields n=0, soinever advances and the result list grows without bound (GC disabled) until the process hangs / OOMs.Both are triggerable from any executed Gravity script — a sandbox-integrity break for embedders running untrusted code.
Fix
Add
utf8_charbytes_safe(), which clamps the reported length to the bytes that remain and never returns less than 1, so every scan both stays in bounds and makes forward progress. All five String call sites (split,loop,iterator,iterator_next,raw) route through it. A truncated or invalid sequence now degrades to a single raw byte instead of reading out of bounds or stalling. The publicutf8_charbytes()signature is unchanged.Verification
heap-buffer-overflow READ, and"\x80abc".split("")hangs until the CPU limit kills it (SIGXCPU).test/unittest/bugfix_utf8_charbytes_bounds.gravity(split DoS, out-of-bounds iteration,raw()on a lone truncated lead byte).🤖 Generated with Claude Code