Skip to content

[Security] BCProvider: unvalidated getLargeHeaderOffset() enables heap OOB read in bytecode parsing #2023

@evilgensec

Description

@evilgensec

Please handle via private channel — I am reporting this here as a fallback since Hermes has no SECURITY.md. Meta's security team may reach me via GitHub (@evilgensec) or through the Meta Bug Bounty program.

Summary

Two heap out-of-bounds read vulnerabilities in BCProviderFromBuffer allow a crafted .hbc bytecode file to trigger OOB memory reads during bytecode loading and execution.

Bug 1: Unvalidated getLargeHeaderOffset() (HIGH)

File: include/hermes/BCGen/HBC/BCProvider.h:459, lib/BCGen/HBC/BCProvider.cpp:658, lib/BCGen/HBC/BCProvider.cpp:725

When a SmallFuncHeader has overflowed=true, getLargeHeaderOffset() (a 32-bit attacker-controlled value) is added directly to bufferPtr_ without bounds checking:

// BCProvider.h:458-460 — no bounds check on getLargeHeaderOffset()
auto large = reinterpret_cast<const hbc::FunctionHeader *>(
    bufferPtr_ + smallHeader.getLargeHeaderOffset());
return RuntimeFunctionHeader(large);

If getLargeHeaderOffset() > fileLength, large points past the bytecode buffer. All subsequent field reads (e.g., getOffset(), getBytecodeSizeInBytes(), flags) are heap OOB reads.

Downstream impact: getBytecode(functionID) at BCProvider.h:495 returns bufferPtr_ + [OOB-read offset], causing the interpreter/JIT to execute arbitrary heap data as bytecode instructions.

Bug 2: Unvalidated overflow string table index (MEDIUM)

File: include/hermes/BCGen/HBC/BCProvider.h:482

When a SmallStringTableEntry has isOverflowed()=true, getOffset() (up to 23 bits, attacker-controlled) is used as an index into overflowStringTableEntries_ without validation against overflowStringCount:

// BCProvider.h:481-482 — getOffset() not bounded by overflowStringCount
if (LLVM_UNLIKELY(smallHeader.isOverflowed())) {
    auto overflow = overflowStringTableEntries_[smallHeader.getOffset()]; // OOB

llvh::ArrayRef::operator[] performs no bounds checking. The returned OOB data is used as an offset+length to construct a StringRef pointing to arbitrary memory.

Attack Surface

  • React Native apps with OTA updates (e.g., CodePush) loading .hbc bundles
  • Any app loading bytecode from external/untrusted sources
  • MITM on OTA update channel → craft malicious .hbc → OOB reads in user device

Suggested Fix

Validate getLargeHeaderOffset() against fileLength - sizeof(FunctionHeader) before use. Validate smallHeader.getOffset() against overflowStringTableEntries_.size() before indexing.


Reported by evilgensec. Full technical details available privately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions