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.
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):
excelize.go:186-193 — OpenReader reads attacker-controlled spreadsheet bytes.excelize.go:216-223 — ZIP reader is created and passed to ReadZipReader.lib.go:43-77 — ZIP entries are read into fileList; worksheet XML is stored by part name.excelize.go:228-229 — XML bytes are stored in f.Pkg.cell.go:71-79 — Public GetCellValue enters the worksheet value-read path.cell.go:1492-1494 — getCellStringFunc calls workSheetReader.excelize.go:313-324 — Worksheet XML is decoded into xlsxWorksheet.xmlWorksheet.go:302-312 — <row r="..."> is deserialized into xlsxRow.R int with no validation (source).excelize.go:357-377 — checkSheet() accumulates the maximum r value; sink: make([]xlsxRow, row) allocates a slice of that size before any bounds check.Vulnerable code (excelize.go:373-377):
if r.R != 0 && r.R > row {
row = r.R
}
sheetData := xlsxSheetData{Row: make([]xlsxRow, row)} // unbounded allocation
The constant TotalRows = 1048576 is defined in...
2.11.0Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:NI:NA:H7.5/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:HResource Management