{"id":"GHSA-c85p-xxjj-2r75","summary":"Excelize ColumnNameToNumber: int64 overflow yields an out-of-domain coordinate with nil error, causing negative slice index panic on r=\"0\" rows","details":"### Summary\n\n`ColumnNameToNumber` (lib.go:220-237) accumulates the bijective base-26 value of a column name in an int64 with only an upper-bound check (`col \u003e MaxColumns`) applied after the loop and no overflow detection. A 14-letter column name whose true value is 3·2⁶⁴ — e.g. **`VGWQHXLSDVIKWV`** — wraps to `col = 0` and passes the guard, so `CellNameToCoordinates(\"VGWQHXLSDVIKWV1\")` returns `(col=0, row=1, err=nil)`.\n\nWhen normalizing a `r=\"0\"` row, `checkSheetR0` (excelize.go:417-443, called from `checkSheet` at excelize.go:405) runs its `checkRow` closure with `col = 0`: `colIdx := col - 1` becomes **-1**, and `sheetData.Row[rowIdx].C[-1]` (excelize.go:424) raises an unrecovered `panic: runtime error: index out of range [-1]`, killing the host process.\n\n### Details\n\n- The row side of the same coordinate gate is enforced (`checkRowNum` at excelize.go:342-350 bounds `r` before the `make([]xlsxRow, row)` allocation; this includes the fix for GHSA-h69g-9hx6-f3v4 / CVE-2026-54063, present in the audited commit). The **column** side is not: `checkSheet`/`lastRowNum`/`checkSheetR0` treat `err == nil` from `CellNameToCoordinates` as proof of an in-domain coordinate (excelize.go:356, :438), which is unsound because of the wrap-around above.\n- The same unsound gate also feeds `ws.SheetData.Row[rowIdx].C[colNum-1]` in `xlsxWorksheet.checkRow` (rows.go:969): a row combining a valid large column (e.g. `XFD1`) with an overflowed column panics identically.\n- Reachable from any `workSheetReader`-based API on an attacker-supplied worksheet: `GetCellValue`, `GetCellFormula`, `SetCellValue`, `GetMergeCells`, `GetSheetDimension`, `GetColWidth`, `AddTable`, etc.\n- Probe on pristine master: `ColumnNameToNumber(\"VGWQHXLSDVIKWV\")` returns `(0, nil)`.\n- This is a distinct root cause from GHSA-h69g-9hx6-f3v4 (row-index allocation): different mechanism (int64 wrap-around → negative index, not oversized allocation), different sink, different fix.\n\n### PoC\n\nA standalone program (public API only) was provided to the maintainer by email (`3-column-overflow`): it builds a workbook in memory whose `xl/worksheets/sheet1.xml` contains `\u003csheetData\u003e\u003crow r=\"0\"\u003e\u003cc r=\"VGWQHXLSDVIKWV1\" t=\"inlineStr\"\u003e\u003cis\u003e\u003ct\u003epwn\u003c/t\u003e\u003c/is\u003e\u003c/c\u003e\u003c/row\u003e\u003c/sheetData\u003e` (\u003c1 KB of attacker XML), calls `OpenReader`, then `GetCellValue(\"Sheet1\", \"A1\")` → `PANIC_REPRODUCED: runtime error: index out of range [-1]` on master `ecd99d761fe0` (2026-09-08). With the proposed patch the same program prints `NO_PANIC_BLOCKED`.\n\n### Impact\n\nA \u003c1 KB crafted `.xlsx` crashes any service that opens a user-supplied spreadsheet and reads it — upload processing, mail-scanning pipelines, spreadsheet conversion endpoints. Remote, unauthenticated, no privileges.\n\n### Proposed fix\n\nBound the accumulated value inside the loop: check `col \u003e MaxColumns` after each digit. Every digit is at least 1, so any name whose true value exceeds MaxColumns crosses the bound inside the loop, before the accumulation can wrap or overflow — this provably covers all cases, including wraps that would land back inside `[1, MaxColumns]`. A complete patch has been provided to the maintainer.","aliases":["CVE-2026-107217"],"modified":"2026-10-07T20:30:05.831565732Z","published":"2026-10-07T20:23:31Z","database_specific":{"nvd_published_at":null,"cwe_ids":["CWE-129","CWE-190"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-10-07T20:23:31Z"},"references":[{"type":"WEB","url":"https://github.com/qax-os/excelize/security/advisories/GHSA-c85p-xxjj-2r75"},{"type":"WEB","url":"https://github.com/qax-os/excelize/pull/2394"},{"type":"WEB","url":"https://github.com/qax-os/excelize/commit/696050fbf14e74e96a58eef2b16aaf72f381a6a8"},{"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.20260910071107-696050fbf14e"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c85p-xxjj-2r75/GHSA-c85p-xxjj-2r75.json"}},{"package":{"name":"github.com/xuri/excelize","ecosystem":"Go","purl":"pkg:golang/github.com/xuri/excelize"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.1.0"},{"last_affected":"1.4.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c85p-xxjj-2r75/GHSA-c85p-xxjj-2r75.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"}]}