Skip to main content
CVE-2026-107223VulnerabilityPublished Updated

github.com/xuri/excelize/v2 · Excelize: Unbounded <col max> attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so

Affects github.com/xuri/excelize/v2Source GCVE Database

0
Compare
Authoritative record:CVE-2026-107223· High 7.1

Not known to be exploited · CVSS 7.1 High : upgrade to 2.11.1 soon.

Data as of 10 Nov 2026, 20:05 UTC

CVSS 4.0 base score
7.1High
How severe the flaw is on the 0–10 CVSS scale.
Patch
Available – fixed in 2.11.1
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Exploitation evidence

  1. Disclosed: evidence found.

    CVE published 7 Oct 2026

  2. Detectable: no evidence on record.

    No public nuclei template indexed

  3. Weaponized: no evidence on record.

    No public exploit code indexed in Metasploit or Exploit-DB

  4. Exploited in the wild: no evidence on record.

    Not in CISA KEV and no source reports exploitation

  5. Observed by OffSeq Mirage: no evidence on record.

    No attack traffic recorded by OffSeq Mirage sensors

A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 10 Nov 2026.

What to do

Upgrade github.com/xuri/excelize/v2 to 2.11.1.

Affected software

ProductAffectedFixed in
Gogithub.com/xuri/excelize/v2Affected
  • >=2.1.0 <2.11.1
Fixed in
  • 2.11.1

Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.

Description

### Summary The `max` attribute of a `<col>` element in `xl/worksheets/sheetN.xml` is read verbatim on open with no check against `MaxColumns`, and `flatCols()` then walks `Min..Max` doing a `deepcopy.Copy` and `append` per iteration. Executed: `max="300000"`, only about 18x past the real 16384 limit, cost 46.2 s of CPU and 122 MB on a single `SetColWidth` call, and the growth is linear in `max` up to 2^31-1. Confirmed at `ae2113b` (HEAD at the time of audit). ### Details `col.go:547`, `flatCols()`, with the two loops at `:549` and `:564`: ```go for i := col.Min; i <= col.Max; i++ { ... for i := column.Min; i <= column.Max; i++ { ... fc = append(fc, deepcopy.Copy(...)) } ``` `column.Min` and `column.Max` are plain int attributes on `xmlWorksheet.go:279-280`, bound straight from the file. `MaxColumns` is 16384 (`templates.go:176`) and nothing in the parse path compares against it. The contrast that makes this an oversight rather than a design decision is inside the callers themselves. `SetColWidth` validates its own column argument through `parseColRange`, which clamps to `MaxColumns`. But `flatCols` iterates `ws.Cols.Col`, the file-loaded slice, so the caller's validated argument never constrains the loop. The crafted column expands no matter which column the caller touches. The row axis has the guard this axis is missing: GHSA-h69g-9hx6-f3v4 capped `checkSheet`'s row allocation at `TotalRows`, and GHSA-q5j5-6p94-4gwc capped streaming `Rows.Next`. There is no column-axis equivalent. Public entry points that flatten the existing columns: `SetColWidth` (`col.go:498` into `:534`), `SetColStyle` (`col.go:431` into `:477`), `SetColVisible` (`col.go:282` into `:313`), `SetColOutlineLevel` (`col.go:376` into `:407`). ### PoC Executed in-package: crafted a real xlsx, rezipped with an injected `<cols>` block before `<sheetData>`, opened it with `OpenReader`, then called `SetColWidth`. ```xml <cols><col min="1" max="2147483647" width="9"/></cols> ``` ```go f.SetColWidth("Sheet1", "A", "A", 12) ``` Measured: - `max="300000"`: 46.2 s CPU, 122 MB allocated, `ws.Cols.Col` grew to 300000 entries, from one call. - `max="5000000"`: did not complete in 110 s, killed by the test timeout. Growth is linear in `max`. At `max=2147483647` that is roughly two billion `xlsxCol` allocations, which is hundreds of gigabytes and in practice a permanent hang ending in OOM. ### Impact Any service that opens an untrusted spreadsheet and calls a column mutator. The input is a few dozen bytes of XML inside an otherwise ordinary workbook, no authentication is involved beyond whatever gates the upload, and the process is either wedged for minutes or killed by the OOM reaper. Availability only; no read or write primitive here. ### Suggested fix Validate `col.Min` and `col.Max` against `MinColumns`/`MaxColumns` when parsing the `<col>` element, or at the top of `flatCols`, returning `ErrColumnNumber` for out-of-range values. That mirrors what `checkRowNum` already does on the row axis. ### Why this is not GHSA-h69g-9hx6-f3v4 or GHSA-q5j5-6p94-4gwc Both of those are row-axis allocation bounds, and both fixes cap at `TotalRows`. Neither touched `<col>` parsing or `flatCols`. This is the same weakness class on the column axis, and it is arguably worse than the two that were fixed, because those had a cap that was bypassed while this one has no cap at all.

References

Community reviews

Loading reviews…