{"id":"CVE-2026-107221","kind":"vulnerability","aliases":["CVE-2026-107221","GHSA-8mcq-6wmr-jrjv","GO-2026-6676"],"related":[],"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.","summary":"Reading an xlsx worksheet with out-of-order cell column references causes the excelize Go library to panic. An attacker who supplies a crafted spreadsheet can crash the process that parses it, a denial of service.","severity":"medium","cvss":6.5,"epss":0.0027,"exploited":false,"exploited_at":null,"products":[{"name":"github.com/xuri/excelize/v2","fixed":["2.11.1-0.20260816084418-46a5eb289448"],"affected":"< 2.11.1-0.20260816084418-46a5eb289448","ecosystem":"go"},{"name":"excelize","fixed":[],"affected":">= 2.0.0, <= 2.11.0","ecosystem":"vendor"},{"name":"github.com/xuri/excelize/v2","fixed":["2.11.1-0.20260816084418-46a5eb289448"],"affected":">= 2.0.0, < 2.11.1-0.20260816084418-46a5eb289448","ecosystem":"go"}],"ecosystems":["go","vendor"],"tags":["cwe-787","excelize","go","package","spreadsheet-parsing"],"not_affected_if":["trusted-input","writes-only"],"how_to_check":"- Look for `github.com/xuri/excelize/v2` in `go.mod` and check the version listed.\n- Run `go list -m github.com/xuri/excelize/v2` in the module to print the resolved version.","fix":"- `github.com/xuri/excelize/v2` `2.11.1-0.20260816084418-46a5eb289448`","status":"open","published_at":"2026-10-07T19:17:34+00:00","first_seen_at":"2026-11-06T00:09:02+00:00","triaged_at":"2026-11-06T00:10:50+00:00","updated_at":"2026-11-06T00:19:08+00:00","category":"package","confidence":0.6,"triage":{"at":"2026-11-06T00:10:50Z","model":"claude-haiku-5-5","output":{"fix":"- `github.com/xuri/excelize/v2` `2.11.1-0.20260816084418-46a5eb289448`","reach":"unknown","title":"Excelize: crafted worksheet cell references make Go reading panic","impact":"low","summary":"Reading an xlsx worksheet with out-of-order cell column references causes the excelize Go library to panic. An attacker who supplies a crafted spreadsheet can crash the process that parses it, a denial of service.","audience":"developers","category":"package","nicknames":[],"who_cares":["go","excelize","spreadsheet-parsing"],"confidence":0.6,"fix_status":"available","needs_auth":"unknown","worst_case":"Parsing process panics, causing denial of service","analyst_note":"","how_to_check":"- Look for `github.com/xuri/excelize/v2` in `go.mod` and check the version listed.\n- Run `go list -m github.com/xuri/excelize/v2` in the module to print the resolved version.","plain_action":"","needs_analyst":false,"not_affected_if":["writes-only","trusted-input"],"who_is_affected":"Go services that open untrusted .xlsx files with excelize's worksheet reading functions are exposed, because a malformed file can trigger the panic. Programs that only write spreadsheets, or that read only files they generated themselves, can skip it. The sources do not say whether recovered panics in HTTP handlers still take down the process.","user_interaction":"no","needs_special_setup":"no","severity_if_unknown":"low"},"cost_usd":0.000687,"input_tokens":4235,"output_tokens":526,"severity_before":"unknown"},"analyst_status":null,"analyst_note":null,"search":"'-1':109C,142C,187C,325C,351C '-107221':29A,40A '-2026':28A,36A,39A '-6676':37A '-787':49B '/xuri/excelize/v2':43A,47A '3':294C,307C,310C '4':293C '6wmr':33A '8mcq':32A 'a1':297C 'ae2113b':100C 'affect':93C 'alloc':127C 'almost':22A 'api':26A,230C 'appear':171C 'assign':192C,363C 'assumpt':212C 'attack':76B,215C 'bash':315C 'bound':348C 'bounds-check':347C 'bug':208C 'c':107C,140C,323C 'calccellvalu':239C 'call':227C,249C 'caus':68B,144C 'cell':6A,15A,65B,122C,138C,152C,156C,169C,184C,276C,285C,289C,334C,342C 'check':349C 'checkrow':112C,113C,235C,301C,319C 'coldata':110C 'colnum':108C,141C,186C,324C,350C 'column':10A,66B,118C,154C,163C,180C,204C,280C,291C,335C 'column-sort':162C 'comput':114C 'concept':268C 'confirm':98C,313C 'craft':80B,270C 'crash':83B,265C 'current':101C 'cve':27A,38A 'cwe':48B 'denial':90B 'determinist':261C 'document':124C,344C 'earlier':5A,172C,284C 'essenti':243C 'everi':23A,136C,202C,244C 'exceed':286C 'excel':1A,50B,70B 'excelize':44A 'excelize.go:332':236C 'execut':269C 'fix':328C 'func':318C 'getcellformula':238C 'getcellstringfunc':299C 'getcellvalu':237C,295C 'getmergecel':240C 'getrow':252C 'ghsa':31A 'ghsa-8mcq-6wmr-jrjv':30A 'github.com':42A,46A 'github.com/xuri/excelize/v2':41A,45A 'go':35A,51B,71B 'goe':232C 'grep':314C 'grow':356C 'head':102C 'help':201C 'higher':9A,179C 'index':17A,303C 'individu':203C 'insid':111C 'jrjv':34A 'last':14A,121C,151C,183C,288C,341C 'lastcol':115C,320C 'len':188C,353C 'length':131C,309C 'librari':72B 'locat':97C 'magnitud':214C 'maxcolumn':197C 'maximum':333C 'model':216C 'n':317C 'need':360C 'non':246C 'non-stream':245C 'open':222C 'order':64B,125C,211C,281C,345C 'out-of-ord':61B 'packag':52B 'panic':16A,74B,263C 'panick':302C 'pars':55B,87B 'path':255C 'process':85B,264C 'proof':266C 'rang':20A,196C,306C 're':134C 're-scatt':133C 'reachabl':218C 'read':25A,56B 'refer':11A,67B,177C 'requir':159C 'rg':316C 'root':143C 'row':3A,175C,253C,274C,321C,338C 'rowidx':106C,322C 'rows.go':326C 'rows.go:940':126C 'rows.go:967':104C,312C 'sax':254C 'scatter':135C 'servic':92B,220C 'setcellvalu':241C 'sheet1':296C 'sink':103C 'size':148C,329C 'slice':146C,358C 'sort':164C 'sourc':137C 'spreadsheet':54B,81B,225C 'spreadsheet-pars':53B 'stream':247C,251C 'suggest':327C 'suppli':78B 'targetlist':128C,189C,330C,354C 'totalrow':198C 'trigger':258C 'unauthent':260C 'unrecov':262C 'untrust':224C 'valid':206C 'version':94C 'via':298C 'vulner':96C 'whose':4A,275C,283C 'worksheet':24A,59B,229C,248C 'worksheetread':234C,300C 'write':193C 'ws.sheetdata.row':105C 'xl/worksheets/sheet1.xml':271C 'xlsx':58B 'xml':167C,292C","nicknames":[],"mitigations":[],"who_affected":"Go services that open untrusted .xlsx files with excelize's worksheet reading functions are exposed, because a malformed file can trigger the panic. Programs that only write spreadsheets, or that read only files they generated themselves, can skip it. The sources do not say whether recovered panics in HTTP handlers still take down the process.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["excelize","githubcomxuriexcelizev2"],"ptokens":["com","excelize","github","v2","xuri"],"labels":["cwe787","excelize","go","medium","package","spreadsheetparsing","vendor"],"campaign_type":null,"first_public_at":"2026-08-16T08:42:11+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"govuln","external_id":"GO-2026-6676","url":"https://pkg.go.dev/vuln/GO-2026-6676","severity":null,"published_at":"2026-11-05T22:53:46+00:00","modified_at":"2026-11-05T22:53:46+00:00","first_seen_at":"2026-11-06T00:09:02+00:00","fetched_at":"2026-11-06T00:09:02+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-107221","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-107221","severity":null,"published_at":"2026-10-07T19:17:34+00:00","modified_at":"2026-10-13T14:22:51+00:00","first_seen_at":"2026-11-06T00:19:01+00:00","fetched_at":"2026-11-06T00:19:01+00:00","note":null},{"source":"ghsa","external_id":"GHSA-8mcq-6wmr-jrjv","url":"https://github.com/advisories/GHSA-8mcq-6wmr-jrjv","severity":"medium","published_at":"2026-10-07T20:23:08+00:00","modified_at":"2026-10-07T20:23:09+00:00","first_seen_at":"2026-11-06T00:19:08+00:00","fetched_at":"2026-11-06T00:19:08+00:00","note":null}],"documents":[{"id":81836,"url":"https://github.com/qax-os/excelize/commit/46a5eb289448e40fbc7d3294589b03861fb822f0","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":81837,"url":"https://github.com/qax-os/excelize/pull/2376","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":81838,"url":"https://github.com/qax-os/excelize/security/advisories/GHSA-8mcq-6wmr-jrjv","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-08-16T08:42:11+00:00","relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"},{"id":81906,"url":"https://api.github.com/repos/qax-os/excelize/security-advisories/GHSA-8mcq-6wmr-jrjv","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"}],"exploit_sources":[{"type":"epss","score":0.0027,"url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107221"}],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}