---
id: "CVE-2026-107221"
page: "https://infrastack.ai/live/CVE-2026-107221"
kind: "vulnerability"
aliases: ["CVE-2026-107221", "GHSA-8mcq-6wmr-jrjv", "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"
severity: "medium"
cvss: 6.5
epss: 0.0027
exploited: false
status: "open"
category: "package"
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"]
published_at: "2026-10-07T19:17:34+00:00"
first_seen_at: "2026-11-06T00:09:02+00:00"
updated_at: "2026-11-06T00:19:08+00:00"
sources: [{"source": "govuln", "url": "https://pkg.go.dev/vuln/GO-2026-6676", "first_seen_at": "2026-11-06T00:09:02+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-107221", "first_seen_at": "2026-11-06T00:19:01+00:00"}, {"source": "ghsa", "url": "https://github.com/advisories/GHSA-8mcq-6wmr-jrjv", "first_seen_at": "2026-11-06T00:19:08+00:00"}]
exploit_sources: [{"type": "epss", "score": 0.0027, "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-107221"}]
---

# 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

Link for people: https://infrastack.ai/live/CVE-2026-107221 (this .md is for agents)

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.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- go:github.com/xuri/excelize/v2 affected < 2.11.1-0.20260816084418-46a5eb289448 fixed 2.11.1-0.20260816084418-46a5eb289448
- vendor:excelize affected >= 2.0.0, <= 2.11.0 fixed no fixed version listed
- go:github.com/xuri/excelize/v2 affected >= 2.0.0, < 2.11.1-0.20260816084418-46a5eb289448 fixed 2.11.1-0.20260816084418-46a5eb289448

## How to check

- Look for `github.com/xuri/excelize/v2` in `go.mod` and check the version listed.
- 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`

## Timeline

- 2026-11-06T00:09:02+00:00 govuln https://pkg.go.dev/vuln/GO-2026-6676
- 2026-11-06T00:19:01+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-107221
- 2026-11-06T00:19:08+00:00 ghsa https://github.com/advisories/GHSA-8mcq-6wmr-jrjv

## Documents

- [advisory] Vendor advisory: github.com https://github.com/qax-os/excelize/security/advisories/GHSA-8mcq-6wmr-jrjv
- [advisory] Maintainer's advisory: api.github.com https://api.github.com/repos/qax-os/excelize/security-advisories/GHSA-8mcq-6wmr-jrjv
- [fix] Patch: github.com https://github.com/qax-os/excelize/commit/46a5eb289448e40fbc7d3294589b03861fb822f0
- [fix] Patch: github.com https://github.com/qax-os/excelize/pull/2376

## From the sources

## Affected versions and vulnerable location

- Confirmed at `ae2113b` (current HEAD).
- Sink: `rows.go:967` `ws.SheetData.Row[rowIdx].C[colNum-1] = *colData` inside `checkRow`.
- `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]`.

## Root cause

The 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.

## Attacker model and reachability

Any 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.

## Proof of concept (executed)

Crafted `xl/worksheets/sheet1.xml` with a row whose cells are out of column order and whose earlier cell exceeds the last cell's column:

```xml
<row r="1"><c r="D1"><v>4</v></c><c r="C1"><v>3</v></c></row>
```

`GetCellValue("Sheet1","A1")` (via `getCellStringFunc -> workSheetReader -> checkRow`) panicked `index out of range [3] with length 3` at `rows.go:967`.

Confirming grep:

```bash
rg -n "func checkRow|lastCol|Row\[rowIdx\].C\[colNum-1\]" rows.go
```

## Suggested fix

Size `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.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
