#6871·assimp

Bug: Hash-collision CPU amplification parsing FBX node/property names

Author: K-ANOYCreated Sep 18, 2026Updated Sep 18, 2026
LabelsBug

The FBX importer stores node names and property names read from the model file into default-hashed std::unordered_maps. On builds with predictable standard-library string hashing, an attacker-supplied .fbx whose node/property names are chosen to land in the same bucket makes insertion (and lookup) during import approach quadratic CPU work. Loading an untrusted model is a normal operation for any application that uses Assimp (game engines, DCC tools, asset pipelines, thumbnailers), so this is reachable without authentication from a single file.

Affected code

std::fbx_unordered_map expands to std::unordered_map on modern builds (code/AssetLib/FBX/FBXCompileConfig.h:70), so the maps below use the default std::hash<std::string>.

Map Key (from the FBX file) Declaration / insertion
FBXConverter::mNodeNames (NodeNameCache) model node name decl FBXConverter.h:455-456; inserted in GetUniqueName at FBXConverter.cpp:512 (and 519 for the de-duplicated name)
PropertyTable::lazyProps (LazyPropertyMap) property name decl FBXProperties.h:96,122; batch-filled from the file at FBXProperties.cpp:180 (lazyProps[name] = ... for every property record)
cpp
// FBXCompileConfig.h
#   define fbx_unordered_map unordered_map          // -> std::unordered_map<std::string, ...>

// FBXProperties.cpp — every property name in the file is inserted into lazyProps
lazyProps[name] = v.second;                         // name = FBX property name

// FBXConverter.cpp — node name from the file; duplicates get a numbered suffix
void FBXConverter::GetUniqueName(const std::string& name, std::string& uniqueName) {
    auto it_pair = mNodeNames.insert({ name, 0 });   // name = FBX node name
    // on a duplicate, a suffixed uniqueName is generated and inserted instead
}

Scope note: PropertyTable::props (PropertyMap) is not part of this finding. It is a lazy per-query cache — PropertyTable::Get(name) inserts a single entry props[name] = ReadTypedProperty(...) only when the caller looks that name up (FBXProperties.cpp:194-201). It is not batch-filled from the file (constructing a table with N file properties leaves lazyProps = N and props = 0), so only lazyProps and mNodeNames receive attacker names in bulk.

Node names are de-duplicated with a numbered suffix in GetUniqueName, so a collision set must consist of distinct node names (each accepted name is inserted once); the collision target is the stored node name.

Trigger and impact

  • Reachable by importing a single untrusted FBX file; no authentication and no accumulation across requests is required.
  • The cited insertion sites have no per-file cap on the number of node/property names.
  • Impact is CPU amplification during import: building lazyProps/mNodeNames from many colliding names is O(n²) (each insert probes the growing bucket), and later PropertyTable::Get lookups are O(bucket size). This report demonstrates map-level degradation, not a specific end-to-end outage.

Suggested fix

  • Use a hash-flooding-resistant (per-process-seeded) hasher for these file-derived name maps, and/or bound the number of node/property names accepted per file.