All projects with patches now have outreach docs. 276 new docs covering CWE-407, CWE-312, CWE-362 across C, C++, Java, Python, Go, Rust, C#, PHP, Ruby, JavaScript, Dart, Erlang, R, and more. Outreach gap: 276 -> 0.
2.7 KiB
LibreOffice — CWE-407 Disclosure Brief (libreoffice-0001)
2026-04-13 · Patch available — awaiting upstream merge
Finding
One O(MC) defect in LibreOffice Calc's pivot table XML export. The SavePivotTableXml() method in xepivotxml.cxx uses std::find on a vector of cache field items to locate the index of each member name, producing O(MC) total cost where M = members and C = cache items.
The Defect
libreoffice-0001 (PATCHED — HIGH): sc/source/filter/excel/xepivotxml.cxx:1404
for (const auto & rMember : aMembers)
{
auto it = std::find(aCacheFieldItems.begin(), aCacheFieldItems.end(),
rMember.maName); // O(C) per member
if (it != aCacheFieldItems.end())
{
size_t nCachePos = std::distance(aCacheFieldItems.begin(), it);
// ...
}
}
For each member M in the pivot field, std::find scans the entire aCacheFieldItems vector (O(C)) to locate the matching cache index. With a text dimension containing thousands of distinct values, both M and C grow large.
Complexity Proof
At M=5,000 members, C=5,000 cache items:
- Defective: 5,000 × 2,500 (avg) = 12,500,000 comparisons
- Fixed: 5,000 (map build) + 5,000 O(1) lookups = 10,000 operations
- ~1,250× op reduction.
Impact
LibreOffice is the most widely used open-source office suite. Pivot tables with text dimensions (product names, customer IDs, city names) commonly contain thousands of distinct values. Saving such spreadsheets to XLSX format triggers the quadratic path for each pivot table dimension.
The Fix
Build a std::unordered_map<OUString, size_t> from cache items before the member loop:
// After
std::unordered_map<OUString, size_t> aCacheItemIndex;
aCacheItemIndex.reserve(aCacheFieldItems.size());
for (size_t k = 0; k < aCacheFieldItems.size(); ++k)
aCacheItemIndex.emplace(aCacheFieldItems[k], k);
for (const auto & rMember : aMembers) {
auto mapIt = aCacheItemIndex.find(rMember.maName);
if (mapIt != aCacheItemIndex.end()) {
size_t nCachePos = mapIt->second; // O(1)
}
}
Patch
Fix available: defects/libreoffice-0001/patch/libreoffice-0001.patch
Single-file patch in sc/source/filter/excel/xepivotxml.cxx. ~1,250× speedup at 5,000 cache items.
What We Ask
A patch is ready for review.
- Confirm receipt and assign a GitHub issue reference (LibreOffice Bugzilla).
- Assess severity — fires on every pivot table save to XLSX, quadratic in dimension cardinality.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
- We will credit the LibreOffice team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.