GHSA-h69g-9hx6-f3v4 Excelize: Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS)
Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS)SummaryThe `checkSheet()` function in `github.com/xuri/excelize/v2` uses an attacker-controlled `<row r="N">` XML attribute value directly as the length argument to `make([]xlsxRow, row)` without validating it against the Excel row limit (`TotalRows = 1,048,576`). A specially crafted XLSX file can trigger two denial-of-service variants: (A) an out-of-memory process kill when `r=2147483647` forces a ~16 GB allocation attempt, and (B) a runtime panic via out-of-bounds slice indexing when `r=-1`. Any service that opens attacker-supplied XLSX files and calls `GetCellValue` is affected. No authentication is required.DetailsThe vulnerable code path is triggered by calling `GetCellValue` (or any API that internally invokes `workSheetReader`) on an XLSX file containing a crafted worksheet row element.**Data flow (source → sink):**`excelize.go:186-193` — `OpenReader` reads attacker-controlled spreadsheet bytes.`excelize.go:216-223` — ZIP reader is created and passed to `ReadZipReader`.`lib.go:43-77` — ZIP entries are read into `fileList`; worksheet XML is stored by part name.`excelize.go:228-229` — XML bytes are stored in `f.Pkg`.`cell.go:71-79` — Public `GetCellValue` enters the worksheet value-read path.`cell.go:1492-1494` — `getCellStringFunc` calls `workSheetReader`.`excelize.go:313-324` — Worksheet XML is decoded into `xlsxWorksheet`.`xmlWorksheet.go:302-312` — `<row r="...">` is deserialized into `xlsxRow.R int` with no validation (source).`excelize.go:357-377` — `checkSheet()` accumulates the maximum `r` value; **sink**: `make([]xlsxRow, row)` allocates a slice of that size before any bounds check.**Vulnerable code (`excelize.go:373-377`):**The constant `TotalRows = 1048576` is defined in `templates.go:190` but is never applied before the `make()` call in `checkSheet()`, leaving the allocation fully attacker-controlled.**Variant A (`r = 2147483647`):** `make([]xlsxRow, 2147483647)` attempts to allocate approximately 16 GB of memory. The Go runtime terminates the process with `fatal error: runtime: out of memory`.**Variant B (`r = -1`):** The first loop in `checkSheet()` leaves `row = 0` because the condition `r.R != 0` is false for `r.R = -1`. The second loop then executes `sheetData.Row[r.R-1]`, which evaluates to `sheetData.Row[-2]`, triggering `runtime error: index out of range [-2]` at `excelize.go:381`.Dynamic reproduction confirmed both variants inside a memory-limited Docker container (256 MB). The full panic stack trace for Variant B is:**Recommended remediation (`excelize.go`):**PoC**Step 1: Generate the malicious XLSX****Step 2: Trigger the vulnerability****Expected results:**Variant A (`r="2147483647"`): process is killed by the OOM killer (`fatal error: runtime: out of memory` or exit code 137).Variant B (`r="-1"`): process panics with `runtime error: index out of range [-2]` at `excelize.go:381` (exit code 2).Both variants were confirmed in a Docker container with `--memory 256m --memory-swap 256m`. The malicious XLSX payload is a few hundred bytes.ImpactThis is a **Denial-of-Service** vulnerability. An unauthenticated remote attacker can crash or memory-exhaust any Go application that uses `github.com/xuri/excelize/v2` to open attacker-supplied XLSX files and subsequently calls any cell-reading API (`GetCellValue`, `GetRows`, `GetCols`, or any function that internally triggers `workSheetReader`).**Who is impacted:**Web services with XLSX upload or import endpoints (document processors, data pipelines, BI tools).CLI tools or batch jobs that parse user-supplied spreadsheet files.Any application using the library to handle untrusted XLSX documents.The attack requires no authentication and no user interaction beyond uploading a malicious file. The payload is a minimal well-formed ZIP of a few hundred bytes, making it trivial to construct and deliver. Repeated or concurrent exploitation can permanently deny service to all users of the affected application.Reproduction artifacts`Dockerfile``poc.py`
CVSS v3.1 score: 7.5