Vulnerability GHSA-x2q3-8cjh-766f
Summary
Excelize: extractPart allocates attacker-controlled, unbounded and negative-sized buffers from CFB directory entries: remote panic / OOM DoS
Details
Summary
extractPart allocates directly from the mscfb directory-entry size with no clamping (crypt.go:198, same missing bound at crypt.go:204):
buf := make([]byte, entry.Size)
entry.Size is the raw streamSize field from the attacker-controlled CFB directory entry (mscfb v1.0.8 fixFile, file.go:109-120: full uint64 → int64 for major version 4, low uint32 for v3). mscfb only detects short sector chains later, inside File.Read (file.go:485-489 "emergency brake") — i.e. after the allocation. The zip path already enforces UnzipSizeLimit, and the KDF path bounds work with maxSpinCount; this path consults no limit at all.
Details
Two consequences, both execution-confirmed against pristine master (ecd99d761fe0, 2026-09-08):
- Hard crash: a version-4 CFB declaring
streamSize = 0xFFFFFFFFFFFFFFFFyieldsentry.Size == -1→panic: runtime error: makeslice: len out of range, which escapesDecrypt(openReaderAtconverts errors, not panics,excelize.go:210-214) and kills the process. - Memory exhaustion: any CFB (v3 suffices) declaring
streamSizeup to0xFFFFFFFFforces up to 4 GiB of zeroed allocation from a ~12 KB file — an amplification factor of ~350,000×, trivially repeated per request in memory-limited deployments.
Call path: OpenFile/OpenReader/OpenBytes → openReaderAt (excelize.go:208-215, OLE magic sniff) → Decrypt (crypt.go:145-150) → extractPart (crypt.go:198).
PoC
A standalone program (public API only) was provided to the maintainer by email (2-extractpart-oom): it builds a valid-enough v4 (4096-byte sector) CFB — header (signature, sector shift 0x0C, DIFAT[0]=1), one directory sector with Root Entry (typeID 5, child=1) and a stream entry EncryptionInfo (objectType=2, startingSector=endOfChain, streamSize=0xFFFFFFFFFFFFFFFF). mscfb.New succeeds, doc.Next() returns the entry, and extractPart calls make([]byte, -1) before any chain validation. On master ecd99d761fe0 the program prints panic: runtime error: makeslice: len out of range; with the proposed patch it prints BLOCKED. An -oom flag demonstrates the 4 GiB allocation variant with streamSize = 0xFFFFFFFF.
Impact
An attacker uploads any file starting with the OLE signature D0 CF 11 E0 A1 B1 1A E1 (~12 KB is enough) to a service that calls excelize.OpenFile/OpenReader/OpenBytes on it (or calls Decrypt directly): remote, unauthenticated process crash (hard panic) or forced 4 GiB allocation per request (OOM) with a ~350,000× amplification factor.
Proposed fix
Bound the declared stream size before allocating in extractPart: reject negative sizes and sizes above a sane policy cap (1 GiB is far above any real encrypted-workbook part) with ErrWorkbookFileFormat, so malformed CFBs are rejected as errors instead of panicking or OOMing. A complete patch has been provided to the maintainer; verified that the patch blocks the PoC while legitimate Encrypt() output still opens.
Related Vulnerabilities
Other vulnerabilities affecting the same packages