Skip to content
Heist/ feed
Back to feed
HighFix available

Excelize: Unbounded attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so any column mutator hangs or OOMs the process

Type: advisorySources: OSV

### Summary The `max` attribute of a `` 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 equivalen

Products
github.com/xuri/excelize/v2
Affected versions
Not specified
Fixed versions
2.11.1-0.20260807015645-a54c578af309
CVEs
CVE-2026-107223
Confirmed fixed CVEs
Not specified
Updated in this feed
28 Oct 2026, 08:47 UTC · Revision 1

Source evidence

Excelize: Unbounded attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so any column mutator hangs or OOMs the process

core-osv · Original source

Published 7 Oct 2026, 20:22 UTC

### Summary The `max` attribute of a `` 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 equivalen

osv:GHSA-fq3v-74gv-27gm

github.com/xuri/excelize/v2

Fixed versions: 2.11.1-0.20260807015645-a54c578af309

Complete source record
{
  "id": "a673028e778c7d2793a5a30901b9e4bc649a7285b461e6ec35324881609e6802",
  "url": "https://osv.dev/vulnerability/GHSA-fq3v-74gv-27gm",
  "method": "structured",
  "payload": {
    "kind": "advisory",
    "title": "Excelize: Unbounded attribute is loaded with no MaxColumns check and expanded per-column by flatCols(), so any column mutator hangs or OOMs the process",
    "summary": "### Summary The `max` attribute of a `` 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 equivalen",
    "evidence": "osv:GHSA-fq3v-74gv-27gm",
    "products": [
      {
        "name": {
          "value": "github.com/xuri/excelize/v2",
          "evidence": "/affected/0/package/name"
        },
        "prerequisites": [],
        "fixed_versions": [
          {
            "value": "2.11.1-0.20260807015645-a54c578af309",
            "evidence": "/affected/0/ranges"
          }
        ],
        "affected_versions": []
      }
    ],
    "severity": "high",
    "structured": {
      "id": "GHSA-fq3v-74gv-27gm",
      "aliases": [
        "CVE-2026-107223",
        "GHSA-fq3v-74gv-27gm"
      ],
      "metrics": [
        {
          "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": [
        {
          "ranges": [
            {
              "type": "SEMVER",
              "events": [
                {
                  "introduced": "2.1.0"
                },
                {
                  "fixed": "2.11.1-0.20260807015645-a54c578af309"
                }
              ]
            }
          ],
          "package": {
            "name": "github.com/xuri/excelize/v2",
            "purl": "pkg:golang/github.com/xuri/excelize/v2",
            "ecosystem": "Go"
          },
          "database_specific": {
            "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-fq3v-74gv-27gm/GHSA-fq3v-74gv-27gm.json"
          }
        }
      ],
      "modified": "2026-10-07T20:30:04.828096632Z",
      "provider": "osv",
      "references": [
        "https://github.com/qax-os/excelize/security/advisories/GHSA-fq3v-74gv-27gm",
        "https://github.com/qax-os/excelize/pull/2370",
        "https://github.com/qax-os/excelize/commit/a54c578af309fa81f448143ed2b7a91192cc58a7",
        "https://github.com/qax-os/excelize"
      ],
      "provider_metadata": {
        "cwe_ids": [
          "CWE-789"
        ],
        "severity": "HIGH",
        "github_reviewed": true,
        "nvd_published_at": null,
        "github_reviewed_at": "2026-10-07T20:22:49Z"
      }
    },
    "related_cves": [
      {
        "value": "CVE-2026-107223",
        "evidence": "/aliases"
      }
    ],
    "security_relevant": true,
    "severity_evidence": "/database_specific/severity"
  },
  "source_id": "core-osv",
  "document_id": 97226,
  "published_at": "2026-10-07T20:22:49+00:00"
}