{"id":"GHSA-8mcq-6wmr-jrjv","summary":"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","details":"## 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 \u003e= 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 -\u003e 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 -\u003e 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\u003crow r=\"1\"\u003e\u003cc r=\"D1\"\u003e\u003cv\u003e4\u003c/v\u003e\u003c/c\u003e\u003cc r=\"C1\"\u003e\u003cv\u003e3\u003c/v\u003e\u003c/c\u003e\u003c/row\u003e\n```\n\n`GetCellValue(\"Sheet1\",\"A1\")` (via `getCellStringFunc -\u003e workSheetReader -\u003e 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.","aliases":["CVE-2026-107221"],"modified":"2026-10-07T20:30:05.928288242Z","published":"2026-10-07T20:23:08Z","database_specific":{"cwe_ids":["CWE-787"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-10-07T20:23:08Z","nvd_published_at":null},"references":[{"type":"WEB","url":"https://github.com/qax-os/excelize/security/advisories/GHSA-8mcq-6wmr-jrjv"},{"type":"WEB","url":"https://github.com/qax-os/excelize/pull/2376"},{"type":"WEB","url":"https://github.com/qax-os/excelize/commit/46a5eb289448e40fbc7d3294589b03861fb822f0"},{"type":"PACKAGE","url":"https://github.com/qax-os/excelize"}],"affected":[{"package":{"name":"github.com/xuri/excelize/v2","ecosystem":"Go","purl":"pkg:golang/github.com/xuri/excelize/v2"},"ranges":[{"type":"SEMVER","events":[{"introduced":"2.0.0"},{"fixed":"2.11.1-0.20260816084418-46a5eb289448"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-8mcq-6wmr-jrjv/GHSA-8mcq-6wmr-jrjv.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H"}]}