Skip to content

← Public intelligence

Go package

github.com/xuri/excelize/v2

Open actionable advisories and recorded vendor fixes. This public package view has no inventory attached and cannot establish whether your deployment is affected. A vendor fix never resolves your finding; verify your installed version and the source guidance.

Open advisories

12 actionable advisories, newest first. Withdrawn advisories and news are excluded. Coverage is partial.

  1. High, CVSS 8.7GoAmendedPublished

    Excelize: Unchecked pivot-cache field index in extractPivotTableFields causes unrecoverable panic

    CVE-2026-107211 · GHSA-mx22-3794-2vpv

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.8.1, < 2.11.1-0.20261003002531-6258dcebc4e2
    Fixed in
    2.11.1-0.20261003002531-6258dcebc4e2· Vendor fix available
    Issue
    extractPivotTableFields builds order := pc.getPivotCacheFieldsName() from xl/pivotCache/pivotCacheDefinitionN.xml's <cacheFields list, then indexes it with values taken from a separately parsed xl/pivotTables/pivotTableN.xml part with zero cross-validation: order[field.Fld] where field.Fld is a raw attacker-controlled int from the <dataField fld="N" attribute, and order[fieldIdx] where fieldIdx is a loop index over pt.PivotFields.PivotField that need not match the cache's field count. I executed two independent PoCs against the current HEAD: (1) trimmed the pivot cache's <cacheFields to count=0 while leaving the pivot table's 2 pivotFields untouched - runtime error: index out of range [0] with length 0 at pivotTable.go:1431; (2) left the 2 cache fields completely intact and only changed one attribute, fld="1" - fld="99999", in xl/pivotTables/pivotTable1.xml - runtime error: index out of range [99999] with length 2 at pivotTable.go:1443. Both stack traces confirmed via…

    Recommended action: Upgrade to 2.11.1-0.20261003002531-6258dcebc4e2 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  2. High, CVSS 8.7GoAmendedPublished

    Excelize: Nil-pointer dereference in GetSlicers when a worksheet has extLst present but no drawing element

    CVE-2026-107213 · GHSA-r7x5-4969-99p7

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.9.0, < 2.11.1-0.20260929015830-8ffeb07ec9a3
    Fixed in
    2.11.1-0.20260929015830-8ffeb07ec9a3· Vendor fix available
    Issue
    GetSlicers guards only if ws.ExtLst == nil { return } (slicer.go:816-818) and then immediately dereferences ws.Drawing.RID with no nil check on ws.Drawing itself. Drawing and ExtLst are two independently optional child elements of <worksheet in xl/worksheets/sheetN.xml, populated separately by encoding/xml depending on whether each tag is present. I executed a PoC: took a plain NewFile() workbook (no drawing, no slicer), saved it, then injected a bare <extLst</extLst immediately before </worksheet in xl/worksheets/sheet1.xml (no other change, no drawing element present) and called GetSlicers. Result: runtime error: invalid memory address or nil pointer dereference, confirmed at the ws.Drawing.RID line via stack trace. Reachability / who can trigger this Unauthenticated: any application that opens an untrusted .xlsx and calls the public File.GetSlicers(sheet) API. The trigger is a single empty XML tag with no valid slicer or drawing content required at all, making it an even…

    Recommended action: Upgrade to 2.11.1-0.20260929015830-8ffeb07ec9a3 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  3. High, CVSS 7.5GoAmendedPublished

    Excelize ANCHORARRAY: mutually-referencing array formulas recurse unboundedly via re-entrant CalcCellValue, causing a fatal stack overflow

    CVE-2026-107216 · GHSA-wp2g-vpjj-g53r

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.8.1, < 2.11.1-0.20260911060113-ea12859e43c6
    Fixed in
    2.11.1-0.20260911060113-ea12859e43c6· Vendor fix available
    Issue
    ANCHORARRAY (calc.go:15137 on current master) evaluates each cell of the referenced spill range by calling the exported CalcCellValue, which unconditionally constructs a fresh calcContext — fresh entry marker, fresh iterations map, full MaxCalcIterations budget (calc.go:896-900). The circular-reference control only exists within one context: the entry-exclusion marker and per-ref iteration budget are fields of that single context, and completion-based caching (formulaArgCache/calcRawCache) only ever stores results of evaluations that finish. During a pure cycle no nested evaluation ever finishes, so nothing is ever cached to break the recursion, and each hop re-arms the entire budget. Two ordinary, Excel-legal constructs in an attacker-supplied workbook are enough: - A1 (dynamic array formula, ref A1:A1): xlfn.ANCHORARRAY($B$1) - B1 (dynamic array formula, ref B1:B1): xlfn.ANCHORARRAY($A$1) → CalcCellValue → calcCellValue → evalInfixExp → parseReference → cellResolver → … →…

    Recommended action: Upgrade to 2.11.1-0.20260911060113-ea12859e43c6 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)osv.dev (2)github.com (3)Source checked Evidence →
  4. Medium, CVSS 5.3GoAmendedPublished

    Excelize: RIGHT() on supplementary-plane text slices with a negative index and panics

    CVE-2026-107218 · GHSA-8jjq-8j9w-m2v6

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.10.1, < 2.11.1-0.20260908032718-ecd99d761fe0
    Fixed in
    2.11.1-0.20260908032718-ecd99d761fe0· Vendor fix available
    Issue
    leftRight (calc.go:14236) tests the length with countUTF16String, which counts a rune above U+FFFF as 2. The RIGHT branch on 14241 then slices []rune(text) at utf8.RuneCountInString(text)-numChars, which counts it as 1. For text with N such runes the two measures are 2N and N, so any numChars between them passes the guard and gives a negative index. The numChars < 0 check at 14216 does not help, since the value that gets through is positive. What makes it worth reporting is AutoFitColWidth, which evaluates formulas without looking like it does, so normalising an uploaded sheet is enough to reach it. One scoping correction to my own wording there: AutoFitColWidth was added in v2.11.0 and does not exist at v2.10.1, so on v2.10.1 the only reachable path is an explicit CalcCellValue. A 6,077-byte file containing two U+1D7D9 characters in A1 and RIGHT(A1,3) in B1 was created and then opened in a separate program without recovery enabled: So it is a regression, not an old defect. Commit…

    Recommended action: Upgrade to 2.11.1-0.20260908032718-ecd99d761fe0 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  5. High, CVSS 7.5GoAmendedPublished

    Excelize: Unbounded spinCount in agile decryption burns CPU during OpenFile

    CVE-2026-107219 · GHSA-jrfj-fhj2-jjvm

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.3.1, < 2.11.1-0.20260906004932-2badfcd5841d
    Fixed in
    2.11.1-0.20260906004932-2badfcd5841d· Vendor fix available
    Issue
    Opening a file whose first eight bytes are the OLE magic number sends excelize down the decryption path whether or not the caller set a password, or supports encrypted workbooks at all. openReaderAt (excelize.go:198-215) branches on the header alone, and agileDecrypt calls convertPasswdToKey before the verifier hash is checked, so the key-derivation loop runs spinCount times regardless. spinCount (crypt.go:98) is a plain int filled by a bare xml.Unmarshal of the file's own EncryptionInfo stream. Nothing bounds it. A 3072-byte file with spinCount 100000000 makes OpenFile take 58.65s on v2.11.0 with default options, then return zip: not a valid zip file. It is linear at about 0.6 microseconds per iteration and the attacker picks the number, so 1e9 is roughly ten minutes. Nothing on the path takes a context.Context, so the caller cannot cancel it; in an HTTP handler the write timeout returns a response while the goroutine keeps spinning. Memory stays flat at 24 MB, so nothing reclaims…

    Recommended action: Upgrade to 2.11.1-0.20260906004932-2badfcd5841d (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  6. Medium, CVSS 6.5GoAmendedPublished

    Excelize: Panic in cellInRange on a worksheet with an empty mergeCell ref

    CVE-2026-107220 · GHSA-g27h-8qhm-6pff

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.7.1, < 2.11.1-0.20260820023833-99903a3240e5
    Fixed in
    2.11.1-0.20260820023833-99903a3240e5· Vendor fix available
    Issue
    A worksheet containing <mergeCell ref=""/ makes mergeCellsParser leave the cached rectangle empty, and cellInRange then indexes that empty slice without a length check. Every non-streaming cell API panics with index out of range [0] with length 0 on the first cell read after opening the file. Where it is cell.go, cellInRange func cellInRange(cell, ref []int) bool { return cell[0] = ref[0] && cell[0] <= ref[2] && cell[1] = ref[1] && cell[1] <= ref[3] } ref is indexed at four positions with no bounds check. The caller that can hand it an empty slice, mergeCellsParser if ref := ws.MergeCells.Cells[i].Ref; len(ws.MergeCells.Cells[i].rect) == 0 && ref != "" { if strings.Count(ref, ":") != 1 { ref += ":" + ref } rect, err := rangeRefToCoordinates(ref) if err != nil { return cell, err } = sortCoordinates(rect) ws.MergeCells.Cells[i].rect = rect } if cellInRange([]int{col, row}, ws.MergeCells.Cells[i].rect) { The ref != "" condition means an empty ref skips the block that populates…

    Recommended action: Upgrade to 2.11.1-0.20260820023833-99903a3240e5 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  7. Medium, CVSS 6.5GoAmendedPublished

    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

    CVE-2026-107221 · GHSA-8mcq-6wmr-jrjv

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.0.0, < 2.11.1-0.20260816084418-46a5eb289448
    Fixed in
    2.11.1-0.20260816084418-46a5eb289448· Vendor fix available
    Issue
    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…

    Recommended action: Upgrade to 2.11.1-0.20260816084418-46a5eb289448 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  8. Medium, CVSS 6.5GoAmendedPublished

    Excelize: GetConditionalFormats indexes conditional-formatting rule sub-elements with no length or nil check

    CVE-2026-107222 · GHSA-rxcj-4pj5-74gr

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.7.0, < 2.11.1-0.20260812075026-be7a16390fa6
    Fixed in
    2.11.1-0.20260812075026-be7a16390fa6· Vendor fix available
    Issue
    GetConditionalFormats reads sub-elements of a <cfRule straight out of xl/worksheets/sheetN.xml and indexes them without checking length, and in one case without checking for nil. Three rule types are affected: cellIs, dataBar and colorScale. A workbook with a rule that is missing a child a real Excel file would always have panics the call. Where it is All three sinks are in styles.go, at the same line numbers in v2.11.0 and on master d552a7e. All three are reached from GetConditionalFormats through styles.go:3271. styles.go:3003, in extractCondFmtCellIs: The branch above it handles len(c.Formula) == 2; this one is the fallback and does not check that there is a formula at all, so a cellIs rule with no <formula child indexes an empty slice. styles.go:3132, in the colorScale extractor: c.ColorScale is a xlsxColorScale and is nil when the <cfRule type="colorScale" element has no <colorScale child. Lines 3148 and 3153 then index Cfvo[1] and Cfvo[2] in the three-colour branch with…

    Recommended action: Upgrade to 2.11.1-0.20260812075026-be7a16390fa6 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  9. High, CVSS 7.1GoAmendedPublished

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

    CVE-2026-107223 · GHSA-fq3v-74gv-27gm

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.1.0, < 2.11.1-0.20260807015645-a54c578af309
    Fixed in
    2.11.1-0.20260807015645-a54c578af309· Vendor fix available
    Issue
    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: 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…

    Recommended action: Upgrade to 2.11.1-0.20260807015645-a54c578af309 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  10. Medium, CVSS 6.5GoAmendedPublished

    Excelize: A Zip64 uncompressed-size of 2^63 panics OpenFile/OpenReader

    CVE-2026-107224 · GHSA-fw94-4wwp-w8pw

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.1.0, < 2.11.1-0.20260805032953-db93f8d89de7
    Fixed in
    2.11.1-0.20260805032953-db93f8d89de7· Vendor fix available
    Issue
    A Zip64 uncompressed-size of 2^63 casts to a negative int64 that bypasses the unzip-size guard and reaches make([]byte, 0, negativeCap) A Zip64 uncompressed-size in the range [2^63, 2^64) casts to a negative int64 in zip.File.FileInfo().Size(), and ReadZipReader does signed arithmetic on that value, so the total-decompression guard is bypassed and the negative size reaches make([]byte, 0, size) in readFile. A 159-byte crafted file panics OpenFile and OpenReader with runtime error: makeslice: cap out of range. The guard, at lib.go:44-46 on HEAD ae2113b: FileInfo().Size() returns int64(UncompressedSize64). UncompressedSize64 is read from the Zip64 extended-information extra record in the central directory and is fully attacker controlled, so any value with the top bit set arrives as a negative int64. unzipSize then goes negative and the comparison against UnzipSizeLimit (default 1000 << 24, templates.go:193) is false no matter how many such entries the archive contains. The…

    Recommended action: Upgrade to 2.11.1-0.20260805032953-db93f8d89de7 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  11. Medium, CVSS 6.5GoAmendedPublished

    Excelize: GetStyle panics on a negative fillId, borderId or fontId in styles.xml

    CVE-2026-107225 · GHSA-5h23-36rv-pm65

    Affected
    • Go github.com/xuri/excelize/v2 >= 2.8.0, < 2.11.1-0.20260731010303-ae2113b410e5
    Fixed in
    2.11.1-0.20260731010303-ae2113b410e5· Vendor fix available
    Issue
    File.GetStyle indexes the fill, border and font tables with values taken straight out of xl/styles.xml, and the conditions gating those lookups check only the upper bound. A workbook whose cellXfs entry carries fillId="-1", borderId="-1" or fontId="-1" reaches a negative slice index and panics. excelize has no recover(), so the panic leaves GetStyle and takes the calling process with it. Same defect class as GHSA-48hm-4h8j-58fg, the negative shared-string index, in a different file. That one was fixed by adding the missing lower bound; these three sites still lack it. Where it is styles.go, in GetStyle, lines 1683, 1686 and 1689: The conditions, at lines 1171 to 1185, bound only the top: xf.FillID < len(...) is satisfied by any negative value. FillID, BorderID and FontID are int unmarshalled directly from the fillId, borderId and fontId attributes, so the value is whatever the file says. The border and font conditions have the same shape. The correct pattern is already in the…

    Recommended action: Upgrade to 2.11.1-0.20260731010303-ae2113b410e5 (pre-release) or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →
  12. High, CVSS 7.5GoAmendedPublished

    Excelize: Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS)

    CVE-2026-54063 · GHSA-h69g-9hx6-f3v4

    Affected
    • Go github.com/xuri/excelize/v2 < 2.11.0
    Fixed in
    2.11.0· Vendor fix available
    Issue
    Unbounded Row Index Allocation in Worksheet Parser (checkSheet OOM/Panic DoS) Summary The checkSheet() function in github.com/xuri/excelize/v2 uses an attacker-controlled <row r="N" XML attribute value directly as the length argument to make([]xlsxRow, row) without validating it against the Excel row limit (TotalRows = 1,048,576). A specially crafted XLSX file can trigger two denial-of-service variants: (A) an out-of-memory process kill when r=2147483647 forces a ~16 GB allocation attempt, and (B) a runtime panic via out-of-bounds slice indexing when r=-1. Any service that opens attacker-supplied XLSX files and calls GetCellValue is affected. No authentication is required. Details The vulnerable code path is triggered by calling GetCellValue (or any API that internally invokes workSheetReader) on an XLSX file containing a crafted worksheet row element. Data flow (source → sink): 1. excelize.go:186-193 — OpenReader reads attacker-controlled spreadsheet bytes. 2. excelize.go:216-223 —…

    Recommended action: Upgrade to 2.11.0 or later, then redeploy and verify.A vendor fix does not resolve your finding until you verify it in your own systems.

    Sources:osv.dev (1)github.com (2)Source checked Evidence →