{"id":"GHSA-8mcq-6wmr-jrjv","revision":"92ab9095cb8a448d81ee28516c2fa779","records":[{"revision":"92ab9095cb8a448d81ee28516c2fa779","observedAt":"2026-11-05T23:38:32.248+00:00","statement":{"source":"osv","id":"GHSA-8mcq-6wmr-jrjv","aliases":["CVE-2026-107221","GO-2026-6676"],"title":"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","description":"## Affected versions and vulnerable location\n\n- Confirmed at `ae2113b` (current HEAD).\n- Sink: `rows.go:967` `ws.SheetData.Row[rowIdx].C[colNum-1] = *colData` inside `checkRow`.\n- `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]`.\n\n## Root cause\n\nThe 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.\n\n## Attacker model and reachability\n\nAny 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.\n\n## Proof of concept (executed)\n\nCrafted `xl/worksheets/sheet1.xml` with a row whose cells are out of column order and whose earlier cell exceeds the last cell's column:\n\n```xml\n<row r=\"1\"><c r=\"D1\"><v>4</v></c><c r=\"C1\"><v>3</v></c></row>\n```\n\n`GetCellValue(\"Sheet1\",\"A1\")` (via `getCellStringFunc -> workSheetReader -> checkRow`) panicked `index out of range [3] with length 3` at `rows.go:967`.\n\nConfirming grep:\n\n```bash\nrg -n \"func checkRow|lastCol|Row\\[rowIdx\\].C\\[colNum-1\\]\" rows.go\n```\n\n## Suggested fix\n\nSize `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.","state":0,"publishedAt":"2026-10-07T20:23:08+00:00","modifiedAt":"2026-11-05T23:26:01.6257129+00:00","affected":[{"ecosystem":"Go","name":"github.com/xuri/excelize/v2","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"2.0.0"},{"kind":"fixed","version":"2.11.1-0.20260816084418-46a5eb289448"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/qax-os/excelize/security/advisories/GHSA-8mcq-6wmr-jrjv","https://github.com/qax-os/excelize/pull/2376","https://github.com/qax-os/excelize/commit/46a5eb289448e40fbc7d3294589b03861fb822f0","https://github.com/qax-os/excelize"],"sourceUrl":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-8mcq-6wmr-jrjv","identifiers":["GHSA-8mcq-6wmr-jrjv","CVE-2026-107221","GO-2026-6676"]},"retained":false,"historicalAffected":[]}],"coverage":[]}