{"schema":"threatline.record/2","record":{"id":"CVE-2026-107221","aliases":["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 >= 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.","categories":["Libraries & packages"],"product":"github.com/xuri/excelize/v2","vendor":"qax-os","ecosystem":"go","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","source_modified_at":"2026-10-07T20:23:09Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/xuri/excelize/v2"},"range":">= 2.0.0, < 2.11.1-0.20260816084418-46a5eb289448"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107221","source_modified_at":"2026-10-07T19:17:06.445Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"excelize","vendor":"qax-os","versions":[{"version":">= 2.0.0, <= 2.11.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-8mcq-6wmr-jrjv","source_modified_at":"2026-10-07T20:30:05.928288242Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"Go","name":"github.com/xuri/excelize/v2","purl":"pkg:golang/github.com/xuri/excelize/v2"},"ranges":[{"events":[{"introduced":"2.0.0"},{"fixed":"2.11.1-0.20260816084418-46a5eb289448"}],"type":"SEMVER"}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","source_modified_at":"2026-10-07T20:23:09Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/xuri/excelize/v2"},"version":"2.11.1-0.20260816084418-46a5eb289448"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-8mcq-6wmr-jrjv","source_modified_at":"2026-10-07T20:30:05.928288242Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"Go","name":"github.com/xuri/excelize/v2","purl":"pkg:golang/github.com/xuri/excelize/v2"},"version":"2.11.1-0.20260816084418-46a5eb289448"}],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":0.0027,"percentile":0.18168,"score_date":"2026-10-23"},"published_at":"2026-10-07T18:41:46.047Z","modified_at":"2026-10-07T20:30:05.928288242Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-07T20:23:09Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107221","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-07T19:17:06.445Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-8mcq-6wmr-jrjv","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-07T20:30:05.928288242Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107221","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/qax-os/excelize/security/advisories/GHSA-8mcq-6wmr-jrjv","tags":["exploit"]},{"source":"CVE List","url":"https://github.com/qax-os/excelize/pull/2376","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/qax-os/excelize/commit/46a5eb289448e40fbc7d3294589b03861fb822f0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-07T19:17:00.546092Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-07T20:30:05.928288242Z","content_hash":"3cc7ffca559b2af8696ebafd84667689ec19ff1e757877e5c42bb005a06ed874"}}
