Excelize: extractPart allocates attacker-controlled, unbounded and negative-sized buffers from CFB directory entries: remote panic / OOM DoS
CVE-2026-107215 · GHSA-x2q3-8cjh-766f · GO-2026-6689 · published 8 Oct 2026
How serious is it
- Severity: high.
- No exploit prediction (EPSS) score yet.
- Not on the CISA list of exploited vulnerabilities.
- No public exploit in Exploit-DB.
Is your app affected by CVE-2026-107215?
Paste this prompt into Claude Code, Cursor or any AI coding tool: it runs a free Shippable scan of your project and fixes what it finds. Built with Lovable, Bolt or v0? Scan your live app. Or upload your package file.
Who is affected
github.com/xuri/excelize/v2(Go) >= 2.3.1, < 2.11.1-0.20260912113515-5f636f9dcde5
How to check
- Run
go list -m github.com/xuri/excelize/v2in your project to see the installed version, including copies pulled in by other packages. - Or paste your lockfile into the checker: it lists every package with a known vulnerability, this one included.
How to fix
Copies a prompt for Claude Code, Cursor or Codex: it checks your lockfiles for this and upgrades it.
- Upgrade
github.com/xuri/excelize/v2to 2.11.1-0.20260912113515-5f636f9dcde5 or later, commit the lockfile and redeploy. - If a vulnerable version was live, check your logs and rotate the secrets that server could read.
The advisory
### Summary
`extractPart` allocates directly from the mscfb directory-entry size with no clamping (`crypt.go:198`, same missing bound at `crypt.go:204`):
```go
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):
1. **Hard crash**: a version-4 CFB declaring `streamSize = 0xFFFFFFFFFFFFFFFF` yields `entry.Size == -1` → `panic: runtime error: makeslice: len out of range`, which escapes `Decrypt` (`openReaderAt` converts errors, not panics, `excelize.go:210-214`) and kills the process.
2. **Memory exhaustion**: any CFB (v3 suffices) declaring `streamSize` up to `0xFFFFFFFF` forces 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.
Check your whole app
Dependencies are only half of it. Free and read-only: before you push, run npx shippable-dev scan localhost:3000 in your project folder, no account needed. For your live app, you prove it's yours with a one-line tag first.
References
- github.com/qax-os/excelize/security/advisories/GHSA-x2q3-8cjh-766f
- github.com/qax-os/excelize/commit/5f636f9dcde55911f14290060b017f0cc88cd694
- github.com/qax-os/excelize/pull/2396
- nvd.nist.gov/vuln/detail/CVE-2026-107215
- github.com/qax-os/excelize
Merged from OSV. Last updated 24 Oct 2026. All vulnerabilities · RSS · JSON