GHSA-C85P-XXJJ-2R75

Vulnerability from github – Published: 2026-10-07 20:23 – Updated: 2026-10-07 20:23
VLAI
Summary
Excelize ColumnNameToNumber: int64 overflow yields an out-of-domain coordinate with nil error, causing negative slice index panic on r="0" rows
Details

Summary

ColumnNameToNumber (lib.go:220-237) accumulates the bijective base-26 value of a column name in an int64 with only an upper-bound check (col > MaxColumns) applied after the loop and no overflow detection. A 14-letter column name whose true value is 3·2⁶⁴ — e.g. VGWQHXLSDVIKWV — wraps to col = 0 and passes the guard, so CellNameToCoordinates("VGWQHXLSDVIKWV1") returns (col=0, row=1, err=nil).

When normalizing a r="0" row, checkSheetR0 (excelize.go:417-443, called from checkSheet at excelize.go:405) runs its checkRow closure with col = 0: colIdx := col - 1 becomes -1, and sheetData.Row[rowIdx].C[-1] (excelize.go:424) raises an unrecovered panic: runtime error: index out of range [-1], killing the host process.

Details

  • The row side of the same coordinate gate is enforced (checkRowNum at excelize.go:342-350 bounds r before the make([]xlsxRow, row) allocation; this includes the fix for GHSA-h69g-9hx6-f3v4 / CVE-2026-54063, present in the audited commit). The column side is not: checkSheet/lastRowNum/checkSheetR0 treat err == nil from CellNameToCoordinates as proof of an in-domain coordinate (excelize.go:356, :438), which is unsound because of the wrap-around above.
  • The same unsound gate also feeds ws.SheetData.Row[rowIdx].C[colNum-1] in xlsxWorksheet.checkRow (rows.go:969): a row combining a valid large column (e.g. XFD1) with an overflowed column panics identically.
  • Reachable from any workSheetReader-based API on an attacker-supplied worksheet: GetCellValue, GetCellFormula, SetCellValue, GetMergeCells, GetSheetDimension, GetColWidth, AddTable, etc.
  • Probe on pristine master: ColumnNameToNumber("VGWQHXLSDVIKWV") returns (0, nil).
  • This is a distinct root cause from GHSA-h69g-9hx6-f3v4 (row-index allocation): different mechanism (int64 wrap-around → negative index, not oversized allocation), different sink, different fix.

PoC

A standalone program (public API only) was provided to the maintainer by email (3-column-overflow): it builds a workbook in memory whose xl/worksheets/sheet1.xml contains <sheetData><row r="0"><c r="VGWQHXLSDVIKWV1" t="inlineStr"><is><t>pwn</t></is></c></row></sheetData> (<1 KB of attacker XML), calls OpenReader, then GetCellValue("Sheet1", "A1") → PANIC_REPRODUCED: runtime error: index out of range [-1] on master ecd99d761fe0 (2026-09-08). With the proposed patch the same program prints NO_PANIC_BLOCKED.

Impact

A <1 KB crafted .xlsx crashes any service that opens a user-supplied spreadsheet and reads it — upload processing, mail-scanning pipelines, spreadsheet conversion endpoints. Remote, unauthenticated, no privileges.

Proposed fix

Bound the accumulated value inside the loop: check col > MaxColumns after each digit. Every digit is at least 1, so any name whose true value exceeds MaxColumns crosses the bound inside the loop, before the accumulation can wrap or overflow — this provably covers all cases, including wraps that would land back inside [1, MaxColumns]. A complete patch has been provided to the maintainer.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/xuri/excelize/v2"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.0.0"
            },
            {
              "fixed": "2.11.1-0.20260910071107-696050fbf14e"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/xuri/excelize"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.1.0"
            },
            {
              "last_affected": "1.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-107217"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-129",
      "CWE-190"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-07T20:23:31Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\n`ColumnNameToNumber` (lib.go:220-237) accumulates the bijective base-26 value of a column name in an int64 with only an upper-bound check (`col \u003e MaxColumns`) applied after the loop and no overflow detection. A 14-letter column name whose true value is 3\u00b72\u2076\u2074 \u2014 e.g. **`VGWQHXLSDVIKWV`** \u2014 wraps to `col = 0` and passes the guard, so `CellNameToCoordinates(\"VGWQHXLSDVIKWV1\")` returns `(col=0, row=1, err=nil)`.\n\nWhen normalizing a `r=\"0\"` row, `checkSheetR0` (excelize.go:417-443, called from `checkSheet` at excelize.go:405) runs its `checkRow` closure with `col = 0`: `colIdx := col - 1` becomes **-1**, and `sheetData.Row[rowIdx].C[-1]` (excelize.go:424) raises an unrecovered `panic: runtime error: index out of range [-1]`, killing the host process.\n\n### Details\n\n- The row side of the same coordinate gate is enforced (`checkRowNum` at excelize.go:342-350 bounds `r` before the `make([]xlsxRow, row)` allocation; this includes the fix for GHSA-h69g-9hx6-f3v4 / CVE-2026-54063, present in the audited commit). The **column** side is not: `checkSheet`/`lastRowNum`/`checkSheetR0` treat `err == nil` from `CellNameToCoordinates` as proof of an in-domain coordinate (excelize.go:356, :438), which is unsound because of the wrap-around above.\n- The same unsound gate also feeds `ws.SheetData.Row[rowIdx].C[colNum-1]` in `xlsxWorksheet.checkRow` (rows.go:969): a row combining a valid large column (e.g. `XFD1`) with an overflowed column panics identically.\n- Reachable from any `workSheetReader`-based API on an attacker-supplied worksheet: `GetCellValue`, `GetCellFormula`, `SetCellValue`, `GetMergeCells`, `GetSheetDimension`, `GetColWidth`, `AddTable`, etc.\n- Probe on pristine master: `ColumnNameToNumber(\"VGWQHXLSDVIKWV\")` returns `(0, nil)`.\n- This is a distinct root cause from GHSA-h69g-9hx6-f3v4 (row-index allocation): different mechanism (int64 wrap-around \u2192 negative index, not oversized allocation), different sink, different fix.\n\n### PoC\n\nA standalone program (public API only) was provided to the maintainer by email (`3-column-overflow`): it builds a workbook in memory whose `xl/worksheets/sheet1.xml` contains `\u003csheetData\u003e\u003crow r=\"0\"\u003e\u003cc r=\"VGWQHXLSDVIKWV1\" t=\"inlineStr\"\u003e\u003cis\u003e\u003ct\u003epwn\u003c/t\u003e\u003c/is\u003e\u003c/c\u003e\u003c/row\u003e\u003c/sheetData\u003e` (\u003c1 KB of attacker XML), calls `OpenReader`, then `GetCellValue(\"Sheet1\", \"A1\")` \u2192 `PANIC_REPRODUCED: runtime error: index out of range [-1]` on master `ecd99d761fe0` (2026-09-08). With the proposed patch the same program prints `NO_PANIC_BLOCKED`.\n\n### Impact\n\nA \u003c1 KB crafted `.xlsx` crashes any service that opens a user-supplied spreadsheet and reads it \u2014 upload processing, mail-scanning pipelines, spreadsheet conversion endpoints. Remote, unauthenticated, no privileges.\n\n### Proposed fix\n\nBound the accumulated value inside the loop: check `col \u003e MaxColumns` after each digit. Every digit is at least 1, so any name whose true value exceeds MaxColumns crosses the bound inside the loop, before the accumulation can wrap or overflow \u2014 this provably covers all cases, including wraps that would land back inside `[1, MaxColumns]`. A complete patch has been provided to the maintainer.",
  "id": "GHSA-c85p-xxjj-2r75",
  "modified": "2026-10-07T20:23:31Z",
  "published": "2026-10-07T20:23:31Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/qax-os/excelize/security/advisories/GHSA-c85p-xxjj-2r75"
    },
    {
      "type": "WEB",
      "url": "https://github.com/qax-os/excelize/pull/2394"
    },
    {
      "type": "WEB",
      "url": "https://github.com/qax-os/excelize/commit/696050fbf14e74e96a58eef2b16aaf72f381a6a8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/qax-os/excelize"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Excelize ColumnNameToNumber: int64 overflow yields an out-of-domain coordinate with nil error, causing negative slice index panic on r=\"0\" rows"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…