Skip to content

fix: bounds-check UTF-8 char length in String methods (GHSA-m75h-734r-wc7j) - #459

Merged
marcobambini merged 1 commit into
masterfrom
fix/utf8-charbytes-bounds
Sep 19, 2026
Merged

marcobambini merged 1 commit into
masterfrom
fix/utf8-charbytes-bounds

Conversation

@marcobambini

Copy link
Copy Markdown
Owner

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:

  • 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 DoSString.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.

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 public utf8_charbytes() signature is unchanged.

Verification

  • Unpatched build under AddressSanitizer: the iteration PoC reports heap-buffer-overflow READ, and "\x80abc".split("") hangs until the CPU limit kills it (SIGXCPU).
  • Patched build: both PoCs run clean under ASan.
  • Added regression test test/unittest/bugfix_utf8_charbytes_bounds.gravity (split DoS, out-of-bounds iteration, raw() on a lone truncated lead byte).
  • Full unit suite passes: 355/355, clean under ASan.

🤖 Generated with Claude Code

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>
@vercel

vercel Bot commented Sep 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
gravity Ready Ready Preview Sep 19, 2026 7:10am UTC

Request Review

@marcobambini
marcobambini merged commit 6712a6b into master Sep 19, 2026
7 checks passed
@marcobambini
marcobambini deleted the fix/utf8-charbytes-bounds branch September 19, 2026 07:16

This branch was successfully deployed

1 active deployment
Preview fa32752f Deployed Sep 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant