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:
-
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.
-
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.
Details
Vulnerability Details
flatbufferse223d69bLocation
include/flatbuffers/idl.h:1079src/idl_parser.cpp:4415include/flatbuffers/reflection_generated.h:1501include/flatbuffers/buffer.h:192Vulnerability Details
src/idl_parser.cpp:4415include/flatbuffers/reflection_generated.h:1501include/flatbuffers/buffer.h:192Parser::Deserialize()checksSchemaBufferHasIdentifier(buf)and the size-prefixed fallback before running the verifier. These identifier helpers performstrncmp()onbuf + 4/buf + 8without first confirming the input is large enough.flatbuffers::Parser::Deserialize(const uint8_t*, size_t)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 callBufferHasIdentifier(), which uses the buffer as though bytes at offsets+4or+8exist. 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
PoC Files
PoC Build
ASAN Result
Attack scenario
Reachability
There are two relevant paths:
Public API path — reproducible
flatbuffers::Parser parser;parser.Deserialize(buf, size);flatcCLI path — reachable but non-triggering in my environmentConfirmed impact
Conservative security impact
Potential impact still unproven
Why the CLI may not crash
In my testing, the direct API PoC reliably triggers ASan, but
flatc --cpp evil.bfbsdoes not. This appears to be becauseflatcloads the file through a wrapper that stores contents instd::string, and the resulting backing allocation masks the short overread for the tested sizes. That does not remove the underlying API bug.