Skip to content

flatbuffers::Parser::Deserialize() performs BFBS identifier probing before running schema verification. Could cause an out-of-bounds read #9023

@Brubbish

Description

@Brubbish

Details

Vulnerability Details

  • Project: flatbuffers
  • Reproduced on local checkout: e223d69b

Location

  • Public declaration:
    • include/flatbuffers/idl.h:1079
  • Vulnerable path:
    • src/idl_parser.cpp:4415
    • include/flatbuffers/reflection_generated.h:1501
    • include/flatbuffers/buffer.h:192
      Vulnerability Details
  • Location:
    • src/idl_parser.cpp:4415
    • include/flatbuffers/reflection_generated.h:1501
    • include/flatbuffers/buffer.h:192
  • Root cause:
    • Parser::Deserialize() checks SchemaBufferHasIdentifier(buf) and the size-prefixed fallback before running the verifier. These identifier helpers perform strncmp() on buf + 4 / buf + 8 without first confirming the input is large enough.
  • Reachability:
    • Public API: flatbuffers::Parser::Deserialize(const uint8_t*, size_t)
    • Real CLI reachability exists through flatc --cpp evil.bfbs, but the wrapper path was non-triggering in the tested setup.

Root Cause

Parser::Deserialize() checks whether the input looks like a BFBS schema by calling identifier helpers before it runs normal verification. Those helpers eventually call BufferHasIdentifier(), which uses the buffer as though bytes at offsets +4 or +8 exist. When the caller passes a very short buffer, this happens before any size-based rejection, so the API performs an out-of-bounds read.

The problem is therefore not in the verifier itself; it is in the pre-verification format probe order.

Because the bug is reproducible through the public API without modifying exports, hooks, or visibility, I believe this should still be treated as a real library vulnerability.

Proof of Concept

Reproduction Environment

  • OS: X64 Debian Trixie container

PoC Files

PoC Build

/usr/bin/clang++ -DFLATBUFFERS_LOCALE_INDEPENDENT=1 -I/work/flatbuffers/include -I/work/flatbuffers/grpc -g -std=c++17 -fPIE -fno-omit-frame-pointer -fsanitize=address,undefined -o /tmp/target5_deserialize_size_poc /tmp/target5_deserialize_size_poc.cpp /work/flatbuffers/build-asan/CMakeFiles/flatc.dir/src/idl_parser.cpp.o /work/flatbuffers/build-asan/CMakeFiles/flatc.dir/src/util.cpp.o

ASAN Result

root@ac391c057a41:/work/flatbuffers# /tmp/target5_deserialize_size_poc
=================================================================
==536==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000014 at pc 0x55ff3964905b bp 0x7fff7ec04880 sp 0x7fff7ec04028
READ of size 1 at 0x502000000014 thread T0
==536==WARNING: invalid path to external symbolizer!
==536==WARNING: Failed to use and restart external symbolizer!
    #0 0x55ff3964905a  (/tmp/target5_deserialize_size_poc+0x16005a) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #1 0x55ff3981d1ba  (/tmp/target5_deserialize_size_poc+0x3341ba) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #2 0x55ff3981d10e  (/tmp/target5_deserialize_size_poc+0x33410e) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #3 0x55ff397dc5f0  (/tmp/target5_deserialize_size_poc+0x2f35f0) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #4 0x55ff3971390d  (/tmp/target5_deserialize_size_poc+0x22a90d) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #5 0x7f55180f9ca7  (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: 58749c528985eab03e6700ebc1469fa50aa41219)
    #6 0x7f55180f9d64  (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: 58749c528985eab03e6700ebc1469fa50aa41219)
    #7 0x55ff3962fba0  (/tmp/target5_deserialize_size_poc+0x146ba0) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)

0x502000000014 is located 3 bytes after 1-byte region [0x502000000010,0x502000000011)
allocated by thread T0 here:
    #0 0x55ff396cf9d3  (/tmp/target5_deserialize_size_poc+0x1e69d3) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #1 0x55ff39713838  (/tmp/target5_deserialize_size_poc+0x22a838) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14)
    #2 0x7f55180f9ca7  (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: 58749c528985eab03e6700ebc1469fa50aa41219)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/tmp/target5_deserialize_size_poc+0x16005a) (BuildId: ede4dc7f326bbd56ddc7b63b82a6ca27ed572b14) 
Shadow bytes around the buggy address:
  0x501ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x501ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x501fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x501fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x502000000000: fa fa[01]fa fa fa 00 fa fa fa fa fa fa fa fa fa
  0x502000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x502000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Attack scenario

Reachability

There are two relevant paths:

  1. Public API path — reproducible

    • flatbuffers::Parser parser;
    • parser.Deserialize(buf, size);
    • This path is sufficient to reproduce the out-of-bounds read with exact-size caller-owned buffers.
  2. flatc CLI path — reachable but non-triggering in my environment
    Confirmed impact

  • Out-of-bounds read via a public library API

Conservative security impact

  • Denial of service / crash

Potential impact still unproven

  • Information disclosure is plausible for an out-of-bounds read, but I have not demonstrated a controlled disclosure primitive
  • I have not demonstrated code execution

Why the CLI may not crash

In my testing, the direct API PoC reliably triggers ASan, but flatc --cpp evil.bfbs does not. This appears to be because flatc loads the file through a wrapper that stores contents in std::string, and the resulting backing allocation masks the short overread for the tested sizes. That does not remove the underlying API bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions