#6792·assimp

Bug: [Vulnerability Report] Heap Buffer Overflow in Assimp FBX Importer

Author: kimkullingCreated Aug 20, 2026Updated Aug 28, 2026
LabelsBugFBXSecurity Risk

Dear Assimp Maintainers,

I am writing to report a heap buffer overflow vulnerability discovered in the FBX importer module of Assimp.

This vulnerability occurs in the aiMaterial::AddBinaryProperty function when loading a malicious FBX file.

Below are the details of the vulnerability.

  1. Environment

OS : Ubuntu 22.04

Version : Assimp 6.0.2 (Latest Release)

Build Type : Release Mode

Build Command:

cmake -S . -B build-afl \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBUILD_SHARED_LIBS=OFF \ -DASSIMP_BUILD_TESTS=OFF \ -DASSIMP_BUILD_SAMPLES=OFF \ -DASSIMP_BUILD_ASSIMP_TOOLS=OFF \ -DASSIMP_BUILD_DRACO=OFF \ -DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=OFF \ -DASSIMP_BUILD_FBX_IMPORTER=ON \ -DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT=OFF

  1. Vulnerability Summary Type : Heap Buffer Overflow Location : code/Material/MaterialSystem.cpp (Line 523) Function : aiMaterial::AddBinaryProperty Vulnerable Code : strcpy(pcNew→mKey.data, pKey)

  2. Root Cause Analysis

The vulnerability arises when adding a property to an aiMaterial object.

The code attempts to copy the property name (pKey) into a fixed-size buffer (pcNew->mKey.data, where AI_MAXLEN = 1024):

// code/Material/MaterialSystem.cpp pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));

// The ai_assert macro is compiled out (empty) in Release builds. ai_assert(AI_MAXLEN > pcNew->mKey.length);

// Vulnerability: No runtime length check exists in Release mode. // If pKey is larger than 1024 bytes, a heap buffer overflow occurs. strcpy(pcNew->mKey.data, pKey);

In Debug builds, ai_assert functions correctly and prevents the overflow.

However, in Release builds (typically used in production), ai_assert is removed during compilation.

Consequently, there is no runtime validation of the string length, allowing an attacker to trigger a heap buffer overflow by providing a property name longer than AI_MAXLEN.

  1. Proof of Concept (PoC)

I have attached:

a PoC FBX file (crash1.1) that triggers this vulnerability, and a test binary (fbx_fuzzer) built with ASAN enabled.

In the PoC, the Opacity property key has been manipulated to contain an abnormally long string.

Snippet of the PoC:

Material: ... { Properties70: { ... P: "OpacityAAAA... (long string) ...AAAA", "double", "Number", "",1 } }     5. ASAN Log  

Running the PoC with AddressSanitizer (ASAN) confirms the heap buffer overflow:

Reading 15599 bytes from crash1.1

==114909==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000008ba0 at pc 0x557de6df4035 bp 0x7ffc9d7080b0 sp 0x7ffc9d707878 WRITE of size 1582 at 0x619000008ba0 thread T0 #0 0x557de6df4034 in strcpy (/root/assimp/build-afl/fbx_fuzzer+0x135034) (BuildId: a53ec1015b595255) #1 0x557de707be24 in aiMaterial::AddBinaryProperty(void const*, unsigned int, char const*, unsigned int, unsigned int, aiPropertyTypeInfo) /root/assimp/code/Material/MaterialSystem.cpp:523:5 #2 0x557de70eb8ad in aiMaterial::AddProperty(float const*, unsigned int, char const*, unsigned int, unsigned int) /root/assimp/include/assimp/material.inl:242:12 #3 0x557de70eb8ad in Assimp::FBX::FBXConverter::SetShadingPropertiesRaw(aiMaterial*, Assimp::FBX::PropertyTable const&, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator>, Assimp::FBX::Texture const*, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator>>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator> const, Assimp::FBX::Texture const*>>> const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:2416:22 #4 0x557de70c9007 in Assimp::FBX::FBXConverter::ConvertMaterial(Assimp::FBX::Material const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1801:5 #5 0x557de715f5b0 in Assimp::FBX::FBXConverter::ConvertMaterialForMesh(aiMesh*, Assimp::FBX::Model const&, Assimp::FBX::MeshGeometry const&, int) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1745:27 #6 0x557de7157254 in Assimp::FBX::FBXConverter::ConvertMeshSingleMaterial(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiMatrix4x4t const&, aiNode*, aiNode*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1238:9 #7 0x557de7149d2c in Assimp::FBX::FBXConverter::ConvertMesh(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1026:20 #8 0x557de7134c04 in Assimp::FBX::FBXConverter::ConvertModel(Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:976:56 #9 0x557de711af50 in Assimp::FBX::FBXConverter::ConvertNodes(unsigned long, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:320:13 #10 0x557de70c755f in Assimp::FBX::FBXConverter::ConvertRootNode() /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:206:5 #11 0x557de70bc379 in Assimp::FBX::FBXConverter::FBXConverter(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:154:5 #12 0x557de71cc346 in Assimp::FBX::ConvertToAssimpScene(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:3812:18 #13 0x557de707e8c4 in Assimp::FBXImporter::InternReadFile(std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, aiScene*, Assimp::IOSystem*) /root/assimp/code/AssetLib/FBX/FBXImporter.cpp:169:3 #14 0x557de6e7aa3a in Assimp::BaseImporter::ReadFile(Assimp::Importer*, std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, Assimp::IOSystem*) /root/assimp/code/Common/BaseImporter.cpp:131:9 #15 0x557de6e57890 in Assimp::Importer::ReadFile(char const*, unsigned int) /root/assimp/code/Common/Importer.cpp:709:30 #16 0x557de6e5197e in Assimp::Importer::ReadFileFromMemory(void const*, unsigned long, unsigned int, char const*) /root/assimp/code/Common/Importer.cpp:507:9 #17 0x557de6e4c71e in LLVMFuzzerTestOneInput /root/assimp/fuzz/fbx_fuzzer.cpp:16:34 #18 0x557de6e46f2d in ExecuteFilesOnyByOne /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c:305:7 #19 0x557de6e46d1d in LLVMFuzzerRunDriver /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c #20 0x557de6e468ad in main /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c:361:10 #21 0x74df4640ad8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #22 0x74df4640ae3f in __libc_start_main csu/../csu/libc-start.c:392:3 #23 0x557de6d84544 in _start (/root/assimp/build-afl/fbx_fuzzer+0xc5544) (BuildId: a53ec1015b595255)

0x619000008ba0 is located 0 bytes to the right of 1056-byte region [0x619000008780,0x619000008ba0) allocated by thread T0 here: #0 0x557de6e441cd in operator new(unsigned long) (/root/assimp/build-afl/fbx_fuzzer+0x1851cd) (BuildId: a53ec1015b595255) #1 0x557de707bc12 in aiMaterial::AddBinaryProperty(void const*, unsigned int, char const*, unsigned int, unsigned int, aiPropertyTypeInfo) /root/assimp/code/Material/MaterialSystem.cpp:510:47 #2 0x557de70eb8ad in aiMaterial::AddProperty(float const*, unsigned int, char const*, unsigned int, unsigned int) /root/assimp/include/assimp/material.inl:242:12 #3 0x557de70eb8ad in Assimp::FBX::FBXConverter::SetShadingPropertiesRaw(aiMaterial*, Assimp::FBX::PropertyTable const&, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator>, Assimp::FBX::Texture const*, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator>>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator> const, Assimp::FBX::Texture const*>>> const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:2416:22 #4 0x557de70c9007 in Assimp::FBX::FBXConverter::ConvertMaterial(Assimp::FBX::Material const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1801:5 #5 0x557de715f5b0 in Assimp::FBX::FBXConverter::ConvertMaterialForMesh(aiMesh*, Assimp::FBX::Model const&, Assimp::FBX::MeshGeometry const&, int) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1745:27 #6 0x557de7157254 in Assimp::FBX::FBXConverter::ConvertMeshSingleMaterial(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiMatrix4x4t const&, aiNode*, aiNode*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1238:9 #7 0x557de7149d2c in Assimp::FBX::FBXConverter::ConvertMesh(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1026:20 #8 0x557de7134c04 in Assimp::FBX::FBXConverter::ConvertModel(Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:976:56 #9 0x557de711af50 in Assimp::FBX::FBXConverter::ConvertNodes(unsigned long, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:320:13 #10 0x557de70c755f in Assimp::FBX::FBXConverter::ConvertRootNode() /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:206:5 #11 0x557de70bc379 in Assimp::FBX::FBXConverter::FBXConverter(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:154:5 #12 0x557de71cc346 in Assimp::FBX::ConvertToAssimpScene(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:3812:18 #13 0x557de707e8c4 in Assimp::FBXImporter::InternReadFile(std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, aiScene*, Assimp::IOSystem*) /root/assimp/code/AssetLib/FBX/FBXImporter.cpp:169:3 #14 0x557de6e7aa3a in Assimp::BaseImporter::ReadFile(Assimp::Importer*, std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, Assimp::IOSystem*) /root/assimp/code/Common/BaseImporter.cpp:131:9 #15 0x557de6e57890 in Assimp::Importer::ReadFile(char const*, unsigned int) /root/assimp/code/Common/Importer.cpp:709:30 #16 0x557de6e5197e in Assimp::Importer::ReadFileFromMemory(void const*, unsigned long, unsigned int, char const*) /root/assimp/code/Common/Importer.cpp:507:9 #17 0x557de6e4c71e in LLVMFuzzerTestOneInput /root/assimp/fuzz/fbx_fuzzer.cpp:16:34 #18 0x557de6e46f2d in ExecuteFilesOnyByOne /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c:305:7

SUMMARY: AddressSanitizer: heap-buffer-overflow (/root/assimp/build-afl/fbx_fuzzer+0x135034) (BuildId: a53ec1015b595255) in strcpy Shadow bytes around the buggy address: 0x0c327fff9120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c327fff9160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c327fff9170: 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff9180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff9190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff91a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff91b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c327fff91c0: 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 ==114909==ABORTING

The report shows a write past the end of a 1056-byte heap region originating from strcpy inside aiMaterial::AddBinaryProperty.

  1. Impact

Since this vulnerability causes heap corruption, it could potentially be exploited for:

denial of service (application crash) remote code execution (RCE), in scenarios where an attacker can supply crafted FBX files and influence heap layout.

I would also like to request a CVE ID to track this vulnerability.

Please let me know if you need any further information

Best regards,

GunP4ng

https://github.com/GunP4ng

[email protected]Dear Assimp Maintainers,

I am writing to report a heap buffer overflow vulnerability discovered in the FBX importer module of Assimp.

This vulnerability occurs in the aiMaterial::AddBinaryProperty function when loading a malicious FBX file.

Below are the details of the vulnerability.

  1. Environment

OS : Ubuntu 22.04

Version : Assimp 6.0.2 (Latest Release)

Build Type : Release Mode

Build Command:

cmake -S . -B build-afl \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DBUILD_SHARED_LIBS=OFF \ -DASSIMP_BUILD_TESTS=OFF \ -DASSIMP_BUILD_SAMPLES=OFF \ -DASSIMP_BUILD_ASSIMP_TOOLS=OFF \ -DASSIMP_BUILD_DRACO=OFF \ -DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=OFF \ -DASSIMP_BUILD_FBX_IMPORTER=ON \ -DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT=OFF

  1. Vulnerability Summary Type : Heap Buffer Overflow Location : code/Material/MaterialSystem.cpp (Line 523) Function : aiMaterial::AddBinaryProperty Vulnerable Code : strcpy(pcNew→mKey.data, pKey)

  2. Root Cause Analysis

The vulnerability arises when adding a property to an aiMaterial object.

The code attempts to copy the property name (pKey) into a fixed-size buffer (pcNew->mKey.data, where AI_MAXLEN = 1024):

// code/Material/MaterialSystem.cpp pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));

// The ai_assert macro is compiled out (empty) in Release builds. ai_assert(AI_MAXLEN > pcNew->mKey.length);

// Vulnerability: No runtime length check exists in Release mode. // If pKey is larger than 1024 bytes, a heap buffer overflow occurs. strcpy(pcNew->mKey.data, pKey);

In Debug builds, ai_assert functions correctly and prevents the overflow.

However, in Release builds (typically used in production), ai_assert is removed during compilation.

Consequently, there is no runtime validation of the string length, allowing an attacker to trigger a heap buffer overflow by providing a property name longer than AI_MAXLEN.

  1. Proof of Concept (PoC)

I have attached:

a PoC FBX file (crash1.1) that triggers this vulnerability, and a test binary (fbx_fuzzer) built with ASAN enabled.

In the PoC, the Opacity property key has been manipulated to contain an abnormally long string.

Snippet of the PoC:

Material: ... { Properties70: { ... P: "OpacityAAAA... (long string) ...AAAA", "double", "Number", "",1 } }     5. ASAN Log  

Running the PoC with AddressSanitizer (ASAN) confirms the heap buffer overflow:

Reading 15599 bytes from crash1.1

==114909==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x619000008ba0 at pc 0x557de6df4035 bp 0x7ffc9d7080b0 sp 0x7ffc9d707878 WRITE of size 1582 at 0x619000008ba0 thread T0 #0 0x557de6df4034 in strcpy (/root/assimp/build-afl/fbx_fuzzer+0x135034) (BuildId: a53ec1015b595255) #1 0x557de707be24 in aiMaterial::AddBinaryProperty(void const*, unsigned int, char const*, unsigned int, unsigned int, aiPropertyTypeInfo) /root/assimp/code/Material/MaterialSystem.cpp:523:5 #2 0x557de70eb8ad in aiMaterial::AddProperty(float const*, unsigned int, char const*, unsigned int, unsigned int) /root/assimp/include/assimp/material.inl:242:12 #3 0x557de70eb8ad in Assimp::FBX::FBXConverter::SetShadingPropertiesRaw(aiMaterial*, Assimp::FBX::PropertyTable const&, std::map<std::__cxx11::basic_string<char, std::char_traits, std::allocator>, Assimp::FBX::Texture const*, std::less<std::__cxx11::basic_string<char, std::char_traits, std::allocator>>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits, std::allocator> const, Assimp::FBX::Texture const*>>> const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:2416:22 #4 0x557de70c9007 in Assimp::FBX::FBXConverter::ConvertMaterial(Assimp::FBX::Material const&, Assimp::FBX::MeshGeometry const*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1801:5 #5 0x557de715f5b0 in Assimp::FBX::FBXConverter::ConvertMaterialForMesh(aiMesh*, Assimp::FBX::Model const&, Assimp::FBX::MeshGeometry const&, int) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1745:27 #6 0x557de7157254 in Assimp::FBX::FBXConverter::ConvertMeshSingleMaterial(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiMatrix4x4t const&, aiNode*, aiNode*) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1238:9 #7 0x557de7149d2c in Assimp::FBX::FBXConverter::ConvertMesh(Assimp::FBX::MeshGeometry const&, Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:1026:20 #8 0x557de7134c04 in Assimp::FBX::FBXConverter::ConvertModel(Assimp::FBX::Model const&, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:976:56 #9 0x557de711af50 in Assimp::FBX::FBXConverter::ConvertNodes(unsigned long, aiNode*, aiNode*, aiMatrix4x4t const&) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:320:13 #10 0x557de70c755f in Assimp::FBX::FBXConverter::ConvertRootNode() /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:206:5 #11 0x557de70bc379 in Assimp::FBX::FBXConverter::FBXConverter(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:154:5 #12 0x557de71cc346 in Assimp::FBX::ConvertToAssimpScene(aiScene*, Assimp::FBX::Document const&, bool) /root/assimp/code/AssetLib/FBX/FBXConverter.cpp:3812:18 #13 0x557de707e8c4 in Assimp::FBXImporter::InternReadFile(std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, aiScene*, Assimp::IOSystem*) /root/assimp/code/AssetLib/FBX/FBXImporter.cpp:169:3 #14 0x557de6e7aa3a in Assimp::BaseImporter::ReadFile(Assimp::Importer*, std::__cxx11::basic_string<char, std::char_traits, std::allocator> const&, Assimp::IOSystem*) /root/assimp/code/Common/BaseImporter.cpp:131:9 #15 0x557de6e57890 in Assimp::Importer::ReadFile(char const*, unsigned int) /root/assimp/code/Common/Importer.cpp:709:30 #16 0x557de6e5197e in Assimp::Importer::ReadFileFromMemory(void const*, unsigned long, unsigned int, char const*) /root/assimp/code/Common/Importer.cpp:507:9 #17 0x557de6e4c71e in LLVMFuzzerTestOneInput /root/assimp/fuzz/fbx_fuzzer.cpp:16:34 #18 0x557de6e46f2d in ExecuteFilesOnyByOne /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c:305:7 #19 0x557de6e46d1d in LLVMFuzzerRunDriver /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c #20 0x557de6e468ad in main /root/AFLplusplus/utils/aflpp_driver/aflpp_driver.c:361:10 #21 0x74df4640ad8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #22 0x74df4640ae3f in __libc_start_main csu/../csu/libc-start.c:392:3 #23 0x557de6d84544 in _start (/root/assimp/build-afl/fbx_fuzzer+0xc5544) (BuildId: a53ec1015b595255)

0x619000008ba0 is located 0 bytes to the right of 1056-byte region [0x619000008780,0x619000008ba0) allocated by thread T0 here: #0 0x557de6e441cd in operator new(unsigned long) (/root/assimp/build-afl/fbx_fuzzer+0x1851cd) (BuildId: a53ec1015b595255) #1 0x557de707bc12