CVE-2026-59161 Overview
CVE-2026-59161 is a resource exhaustion vulnerability in Excelize, a Go language library for reading and writing Microsoft Excel spreadsheets. Versions prior to 2.11.0 do not enforce the TotalRows limit on the row r attribute in the streaming worksheet reader used by Rows and GetRows. An attacker can craft a small XLSX file specifying a row number above 1048576 with no cell coordinate, forcing GetRows to append empty rows up to the attacker-controlled index. This consumes excessive memory and CPU, resulting in denial of service against any application parsing untrusted spreadsheet input.
Critical Impact
A malicious XLSX file weighing only a few kilobytes can exhaust server memory and CPU, disrupting availability of Go services that parse untrusted spreadsheets.
Affected Products
- Excelize (github.com/xuri/excelize / qax-os/excelize) versions prior to 2.11.0
- Go applications invoking Rows on untrusted XLSX input
- Go applications invoking GetRows on untrusted XLSX input
Discovery Timeline
- 2026-07-10 - CVE-2026-59161 published to NVD
- 2026-07-16 - Last updated in NVD database
Technical Details for CVE-2026-59161
Vulnerability Analysis
Excelize exposes a TotalRows configuration option intended to cap the number of rows returned by the streaming reader. The streaming worksheet parser reads the r attribute on each <row> element to determine the row index in the resulting slice. Prior to 2.11.0, the reader trusted this attribute without validating it against TotalRows or the XLSX specification maximum of 1048576.
When a row element declares r="9999999999" and contains no cell coordinates, GetRows fills the intermediate positions with empty rows up to that index. The library allocates memory proportional to the attacker-supplied integer, not to the actual file size. This behavior maps to CWE-400, Uncontrolled Resource Consumption.
Root Cause
The streaming reader in cell.go and related worksheet parsing routines derived the output row count directly from the r XML attribute. No bounds check compared the parsed value against TotalRows or the Excel row ceiling of 1048576 before growing the result slice.
Attack Vector
Exploitation requires only that a target application call Rows or GetRows on an attacker-supplied XLSX file. This is common in file upload endpoints, data import pipelines, and email attachment processors. No authentication, user interaction, or valid Excel content is required. The malicious payload is a single <row r="..."> element with an inflated index.
// Security patch in cell.go (excerpt) - qax-os/excelize commit 93f0b3c
// Fixes GHSA-q5j5-6p94-4gwc and GHSA-fx5j-qcqg-grpf (#2331)
d.mu.Lock()
defer d.mu.Unlock()
- if len(d.SI) > xlsxSI {
- return f.formattedValue(&xlsxC{S: c.S, V: d.SI[xlsxSI].String()}, raw, CellTypeSharedString)
+ if xlsxSI < 0 || xlsxSI >= len(d.SI) {
+ return "", newInvalidSharedStringIndex(xlsxSI)
}
+ return f.formattedValue(&xlsxC{S: c.S, V: d.SI[xlsxSI].String()}, raw, CellTypeSharedString)
Source: qax-os/excelize commit 93f0b3c
The patch also introduces a dedicated error constructor for invalid indices in errors.go, hardening related index validation across the parser.
Detection Methods for CVE-2026-59161
Indicators of Compromise
- XLSX uploads under 100 KB that trigger sustained high memory or CPU usage in Go worker processes.
- Application logs showing prolonged GetRows or Rows calls without returning results.
- OOM (out-of-memory) kills on services that ingest spreadsheets from external sources.
- XLSX sheet.xml entries containing <row r="N"> where N exceeds 1048576.
Detection Strategies
- Inspect uploaded XLSX archives and flag any <row> element whose r attribute exceeds the Excel maximum of 1048576.
- Instrument Excelize call sites with timeouts and memory ceilings, alerting when a single parse operation exceeds a defined threshold.
- Use Go dependency scanning (govulncheck, go list -m -u) to identify modules pinned below excelize v2.11.0.
Monitoring Recommendations
- Track per-process resident set size (RSS) and goroutine count for services parsing user-supplied spreadsheets.
- Log the size, source, and parse duration of every XLSX file processed, correlating anomalies with the uploading identity.
- Alert on repeated OOM events or CPU saturation on ingestion workers, which may indicate exploitation attempts.
How to Mitigate CVE-2026-59161
Immediate Actions Required
- Upgrade Excelize to version 2.11.0 or later in all Go services.
- Audit code paths that call Rows or GetRows on untrusted input and verify they use bounded goroutines and timeouts.
- Enforce request-level memory and CPU limits on services that accept XLSX uploads.
- Rebuild and redeploy any container images that vendor the vulnerable library version.
Patch Information
The issue is fixed in Excelize 2.11.0. See the GitHub Security Advisory GHSA-q5j5-6p94-4gwc, Pull Request #2331, and the v2.11.0 Release Notes. Update your go.mod with go get github.com/xuri/excelize/v2@v2.11.0 and run go mod tidy.
Workarounds
- Pre-validate uploaded XLSX files by unzipping and inspecting xl/worksheets/*.xml for row r attributes greater than 1048576, rejecting them before invocation.
- Set an explicit TotalRows option and wrap parse calls in context.WithTimeout to bound execution time even though the flaw bypasses TotalRows.
- Run Excelize parsing in a sandboxed subprocess with cgroup memory limits so a single malicious file cannot exhaust the parent service.
# Upgrade to the patched version
go get github.com/xuri/excelize/v2@v2.11.0
go mod tidy
# Verify the resolved version
go list -m github.com/xuri/excelize/v2
# Scan for remaining vulnerable dependencies
govulncheck ./...
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

