~ / search / GHSA-8mcq-6wmr-jrjv

GHSA-8mcq-6wmr-jrjv

Excelize: a row whose earlier cell has a higher column reference than its last cell panics index out of range on almost every worksheet read API

Source: GitHub Advisory Database (reviewed) Moderate CVE-2026-107221

Packages

EcosystemPackageAffectedFixed in
Go github.com/xuri/excelize/v2 >= 2.0.0, < 2.11.1-0.20260816084418-46a5eb289448 2.11.1-0.20260816084418-46a5eb289448

Details

As written in the advisory (Markdown source, shown as plain text).

## Affected versions and vulnerable location - Confirmed at `ae2113b` (current HEAD). - Sink: `rows.go:967` `ws.SheetData.Row[rowIdx].C[colNum-1] = *colData` inside `checkRow`. - `checkRow` computes `lastCol` from the column of the last cell in document order (`rows.go:940`), allocates `targetList` of that length, then re-scatters every source cell into `C[colNum-1]`. ## Root cause The slice is sized from the last cell's column, but cells are not required to be column-sorted in the XML. A cell that appears earlier in the row but references a higher column than the last cell has `colNum-1 >= len(targetList)`, so the assignment writes out of range. `MaxColumns`/`TotalRows` do not help, every individual column is valid; the bug is the ordering assumption, not magnitude. ## Attacker model and reachability Any service that opens an untrusted spreadsheet and calls a worksheet API that goes through `workSheetReader -> checkRow` (`excelize.go:332`): `GetCellValue`, `GetCellFormula`, `CalcCellValue`, `GetMergeCells`, `SetCellValue`, and essentially every non-streaming worksheet call. (The streaming `GetRows`/`Rows()` SAX path does not trigger it.) Unauthenticated, deterministic, unrecovered panic -> process crash. ## Proof of concept (executed) Crafted `xl/worksheets/sheet1.xml` with a row whose cells are out of column order and whose earlier cell exceeds the last cell's column: ```xml <row r="1"><c r="D1"><v>4</v></c><c r="C1"><v>3</v></c></row> ``` `GetCellValue("Sheet1","A1")` (via `getCellStringFunc -> workSheetReader -> checkRow`) panicked `index out of range [3] with length 3` at `rows.go:967`. Confirming grep: ```bash rg -n "func checkRow|lastCol|Row\[rowIdx\].C\[colNum-1\]" rows.go ``` ## Suggested fix Size `targetList` from the maximum cell column in the row (not the last cell in document order), or bounds-check `colNum-1` against `len(targetList)` and grow the slice as needed before the assignment.

References

External links from the advisory. They lead to third-party sites.