CVE-2026-107223: Excelize Unbounded <col Max> Attribute Is Vulnerability

HIGH
Advisory Identifier: GHSA-fq3v-74gv-27gm
CWE-789
Published
Advisory Summary

CVE-2026-107223 is a HIGH unbounded <col max> attribute is vulnerability (CWE-789: Memory Allocation with Excessive Size Value) affecting Excelize libraries in the Go ecosystem. The issue involves unbounded <col max> attribute is loaded with no maxcolumns check and expanded per-column by flatcols(), so any column mutator hangs or ooms the process. Remediation is available by upgrading affected packages to version 2.11.1-0.20260807015645-a54c578af309.

CVE-2026-107223 at a Glance

CVE Identifier CVE-2026-107223
GHSA Identifier GHSA-fq3v-74gv-27gm
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-789: Memory Allocation with Excessive Size Value
Affected Product Excelize
Package Ecosystem Go
Published Date
Last Updated

How to Fix CVE-2026-107223

To remediate this vulnerability, upgrade all affected Excelize dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/xuri/excelize/v2 fixed: 2.11.1-0.20260807015645-a54c578af309
Upgrade github.com/xuri/excelize/v2 to 2.11.1-0.20260807015645-a54c578af309
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/xuri/excelize/v2

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-107223, inspect your project dependencies for Excelize:

inspect dependencies for github.com/xuri/excelize/v2

Analyze the terminal output to locate any version of Excelize in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.11.1-0.20260807015645-a54c578af309), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-789: Memory Allocation with Excessive Size Value, where the product allocates memory based on an untrusted, large size value, but it does not ensure that the size is within expected limits, allowing arbitrary amounts of memory to be allocated. In Excelize, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

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

CVE-2026-107223 Affected Excelize Versions

1 component(s)
Fixed Versions:
2.11.1-0.20260807015645-a54c578af309
Product / Package Ecosystem Affected Versions Fixed Version
github.com/xuri/excelize/v2
Go
≥ 2.1.0
< 2.11.1-0.20260807015645-a54c578af309
2.11.1-0.20260807015645-a54c578af309

References

Frequently Asked Questions

What is CVE-2026-107223?
CVE-2026-107223 is a security vulnerability in Excelize involving Unbounded <col max> attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so any column mutator hangs or OOMs the process under CWE-789: Memory Allocation with Excessive Size Value.
Which Excelize versions are affected?
Affected versions include releases prior to 2.11.1-0.20260807015645-a54c578af309 across affected packages: github.com/xuri/excelize/v2.
What version fixes CVE-2026-107223?
Upgrading to 2.11.1-0.20260807015645-a54c578af309 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/xuri/excelize/v2 affected?
Yes, github.com/xuri/excelize/v2 is affected in releases prior to 2.11.1-0.20260807015645-a54c578af309. Upgrade your dependency to 2.11.1-0.20260807015645-a54c578af309 or later.
What CWE is associated with CVE-2026-107223?
CVE-2026-107223 is classified under CWE-789: Memory Allocation with Excessive Size Value (The product allocates memory based on an untrusted, large size value, but it does not ensure that the size is within expected limits, allowing arbitrary amounts of memory to be allocated.).
How can I check Go dependencies for CVE-2026-107223?
Run the dependency tree command: 'inspect dependencies for github.com/xuri/excelize/v2'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-fq3v-74gv-27gm",
  "modified" : "2026-10-07T20:22:49Z",
  "published" : "2026-10-07T20:22:49Z",
  "aliases" : [ "CVE-2026-107223" ],
  "summary" : "Excelize: Unbounded <col max> attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so any column mutator hangs or OOMs the process",
  "details" : "### Summary\n\nThe `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.\n\nConfirmed at `ae2113b` (HEAD at the time of audit).\n\n### Details\n\n`col.go:547`, `flatCols()`, with the two loops at `:549` and `:564`:\n\n```go\nfor i := col.Min; i <= col.Max; i++ {\n...\nfor i := column.Min; i <= column.Max; i++ { ... fc = append(fc, deepcopy.Copy(...)) }\n```\n\n`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.\n\nThe 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.\n\nThe 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.\n\nPublic 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`).\n\n### PoC\n\nExecuted in-package: crafted a real xlsx, rezipped with an injected `<cols>` block before `<sheetData>`, opened it with `OpenReader`, then called `SetColWidth`.\n\n```xml\n<cols><col min=\"1\" max=\"2147483647\" width=\"9\"/></cols>\n```\n\n```go\nf.SetColWidth(\"Sheet1\", \"A\", \"A\", 12)\n```\n\nMeasured:\n\n- `max=\"300000\"`: 46.2 s CPU, 122 MB allocated, `ws.Cols.Col` grew to 300000 entries, from one call.\n- `max=\"5000000\"`: did not complete in 110 s, killed by the test timeout.\n\nGrowth 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.\n\n### Impact\n\nAny 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.\n\n### Suggested fix\n\nValidate `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.\n\n### Why this is not GHSA-h69g-9hx6-f3v4 or GHSA-q5j5-6p94-4gwc\n\nBoth 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.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "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"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/xuri/excelize/v2"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2.1.0"
      }, {
        "fixed" : "2.11.1-0.20260807015645-a54c578af309"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/qax-os/excelize/security/advisories/GHSA-fq3v-74gv-27gm"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/qax-os/excelize/pull/2370"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/qax-os/excelize/commit/a54c578af309fa81f448143ed2b7a91192cc58a7"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/qax-os/excelize"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-789" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-10-07T20:22:49Z",
    "nvd_published_at" : null
  }
}