| Title | openbabel master-branch Heap-based Buffer Overflow |
|---|
| Description | ## Heap-buffer-overflow (Read) in OpenBabel::transform3d::DescribeAsString (transform3d.cpp:60)
### Description
We discovered a Heap-buffer-overflow (Read) vulnerability in OpenBabel. The crash occurs in OpenBabel::transform3d::DescribeAsString when parsing a malformed MMCIF/CIF file involving Space Group definitions.
The ASAN report indicates a READ of size 8 occurring exactly 0 bytes after a 96-byte allocated region. This suggests the code attempts to read a double value (8 bytes) past the end of a transformation matrix buffer (likely containing 12 doubles).
### Environment
- OS: Linux x86_64
- Complier: Clang
- Build Configuration: Release mode with ASan enabled.
### Vulnerability Details
- Target: OpenBabel
- Vulnerability Type: CWE-125: Out-of-bounds Read
- Function: OpenBabel::transform3d::DescribeAsString
- Location: src/math/transform3d.cpp:60:18
- Caller: OpenBabel::SpaceGroup::AddTransform at src/math/spacegroup.cpp:308
- Allocation Site: OpenBabel::SpaceGroup::AddTransform (allocating 96 bytes)
- Root Cause Analysis: The buffer is allocated with a size of 96 bytes, which corresponds to 12 double values (likely a 3x4 matrix representation). However, the DescribeAsString function at line 60 attempts to access memory beyond this limit (offset 96), likely trying to access a 13th element. This often happens if the code assumes a 4x4 matrix layout (16 elements) or has an off-by-one error in a loop iterating over the matrix components.
### Reproduce
1. Build openbabel with Release optimization and ASAN enabled.
```
CC=clang CXX=clang++ cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_ASAN=ON \
-DCMAKE_CXX_FLAGS="-g -fsanitize=address -O3" \
-DCMAKE_C_FLAGS="-g -fsanitize=address -O3"
make -j$(nproc)
```
2. Set runtime configuration
```
export REPRO_BUILD_DIR="/src/repro/openbabel/build"
export BABEL_LIBDIR="$REPRO_BUILD_DIR/lib"
export LD_LIBRARY_PATH="$REPRO_BUILD_DIR/lib:$LD_LIBRARY_PATH"
export ASAN_OPTIONS="symbolize=1:detect_leaks=0:detect_odr_violation=0:allocator_may_return_null=1:abort_on_error=1"
```
3. Run with the crashing [file](https://github.com/oneafter/0128/blob/main/ob1/repro.cif):
```
obabel -icif repro.cif -osmi -O /dev/null
```
<details>
<summary>ASAN report</summary>
```
==63235==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x508000004000 at pc 0x7f3c7c6312c4 bp 0x7ffed6c6c550 sp 0x7ffed6c6c548
READ of size 8 at 0x508000004000 thread T0
#0 0x7f3c7c6312c3 in OpenBabel::transform3d::DescribeAsString[abi:cxx11]() const /src/repro/openbabel/src/math/transform3d.cpp:60:18
#1 0x7f3c7c6271e3 in OpenBabel::SpaceGroup::AddTransform(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/repro/openbabel/src/math/spacegroup.cpp:308:22
#2 0x7f3c7c624a10 in OpenBabel::SpaceGroups::ParseLine(char const*) /src/repro/openbabel/src/math/spacegroup.cpp:140:18
#3 0x7f3c7c2dd973 in OpenBabel::OBGlobalDataBase::Init() /src/repro/openbabel/src/data.cpp:706:17
#4 0x7f3c7c6283e2 in OpenBabel::SpaceGroup::GetSpaceGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/repro/openbabel/src/math/spacegroup.cpp:388:20
#5 0x7f3c7613ae90 in OpenBabel::OBUnitCell::SetSpaceGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/repro/openbabel/include/openbabel/generic.h:364:62
#6 0x7f3c7613ae90 in OpenBabel::mmCIFFormat::ReadMolecule(OpenBabel::OBBase*, OpenBabel::OBConversion*) /src/repro/openbabel/src/formats/mmcifformat.cpp:970:17
#7 0x7f3c766aa82f in OpenBabel::CIFFormat::ReadMolecule(OpenBabel::OBBase*, OpenBabel::OBConversion*) /src/repro/openbabel/src/formats/cifformat.cpp:1402:38
#8 0x7f3c7c56d433 in OpenBabel::OBMoleculeFormat::ReadChemObjectImpl(OpenBabel::OBConversion*, OpenBabel::OBFormat*) /src/repro/openbabel/src/obmolecformat.cpp:101:18
#9 0x7f3c7c47a7fc in OpenBabel::OBConversion::Convert() /src/repro/openbabel/src/obconversion.cpp:542:30
#10 0x7f3c7c479d8b in OpenBabel::OBConversion::Convert(std::istream*, std::ostream*) /src/repro/openbabel/src/obconversion.cpp:478:17
#11 0x7f3c7c483d16 in OpenBabel::OBConversion::FullConvert(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&) /src/repro/openbabel/src/obconversion.cpp:1511:17
#12 0x55b15ae85193 in main /src/repro/openbabel/tools/obabel.cpp:370:20
#13 0x7f3c7bbe21c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#14 0x7f3c7bbe228a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#15 0x55b15ada8584 in _start (/src/repro/openbabel/build/bin/obabel+0x2e584) (BuildId: c5e5db55bc93a5bc1c6dc818a9b2a6e4170c0137)
0x508000004000 is located 0 bytes after 96-byte region [0x508000003fa0,0x508000004000)
allocated by thread T0 here:
#0 0x55b15ae819f1 in operator new(unsigned long) (/src/repro/openbabel/build/bin/obabel+0x1079f1) (BuildId: c5e5db55bc93a5bc1c6dc818a9b2a6e4170c0137)
#1 0x7f3c7c6270e7 in OpenBabel::SpaceGroup::AddTransform(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/repro/openbabel/src/math/spacegroup.cpp:303:30
#2 0x7f3c7c624a10 in OpenBabel::SpaceGroups::ParseLine(char const*) /src/repro/openbabel/src/math/spacegroup.cpp:140:18
#3 0x7f3c7c2dd973 in OpenBabel::OBGlobalDataBase::Init() /src/repro/openbabel/src/data.cpp:706:17
#4 0x7f3c7c6283e2 in OpenBabel::SpaceGroup::GetSpaceGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&) /src/repro/openbabel/src/math/spacegroup.cpp:388:20
#5 0x7f3c7613ae90 in OpenBabel::OBUnitCell::SetSpaceGroup(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>) /src/repro/openbabel/include/openbabel/generic.h:364:62
#6 0x7f3c7613ae90 in OpenBabel::mmCIFFormat::ReadMolecule(OpenBabel::OBBase*, OpenBabel::OBConversion*) /src/repro/openbabel/src/formats/mmcifformat.cpp:970:17
#7 0x7f3c766aa82f in OpenBabel::CIFFormat::ReadMolecule(OpenBabel::OBBase*, OpenBabel::OBConversion*) /src/repro/openbabel/src/formats/cifformat.cpp:1402:38
#8 0x7f3c7c56d433 in OpenBabel::OBMoleculeFormat::ReadChemObjectImpl(OpenBabel::OBConversion*, OpenBabel::OBFormat*) /src/repro/openbabel/src/obmolecformat.cpp:101:18
#9 0x7f3c7c47a7fc in OpenBabel::OBConversion::Convert() /src/repro/openbabel/src/obconversion.cpp:542:30
#10 0x7f3c7c479d8b in OpenBabel::OBConversion::Convert(std::istream*, std::ostream*) /src/repro/openbabel/src/obconversion.cpp:478:17
#11 0x7f3c7c483d16 in OpenBabel::OBConversion::FullConvert(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>&) /src/repro/openbabel/src/obconversion.cpp:1511:17
#12 0x55b15ae85193 in main /src/repro/openbabel/tools/obabel.cpp:370:20
#13 0x7f3c7bbe21c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#14 0x7f3c7bbe228a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 274eec488d230825a136fa9c4d85370fed7a0a5e)
#15 0x55b15ada8584 in _start (/src/repro/openbabel/build/bin/obabel+0x2e584) (BuildId: c5e5db55bc93a5bc1c6dc818a9b2a6e4170c0137)
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/repro/openbabel/src/math/transform3d.cpp:60:18 in OpenBabel::transform3d::DescribeAsString[abi:cxx11]() const
Shadow bytes around the buggy address:
0x508000003d80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
0x508000003e00: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
0x508000003e80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
0x508000003f00: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
0x508000003f80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
=>0x508000004000:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000004080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000004100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000004180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000004200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x508000004280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==63235==ABORTING
```
</details> |
|---|
| Source | ⚠️ https://github.com/openbabel/openbabel/issues/2848 |
|---|
| User | Oneafter (UID 92781) |
|---|
| Submission | 02/09/2026 02:13 (5 months ago) |
|---|
| Moderation | 02/18/2026 19:05 (10 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 346650 [Open Babel up to 3.1.1 CIF File src/math/transform3d.cpp DescribeAsString out-of-bounds] |
|---|
| Points | 20 |
|---|