GITHUB.COM/XURI/EXCELIZE/V2 · CVE-2026-107225 · Package
FIX → 2.11.1-0.20260731010303-ae2113b410e5
The Excelize Go library panics in GetStyle when a spreadsheet's styles.xml contains a negative fillId, borderId or fontId. An attacker who supplies a crafted .xlsx file can crash a program that reads it, causing a denial of service.
first public Jul 31, 2026 · 3 sources
Check it with your coding agent
It checks your repository and tells you if you’re affected, with the fix.
Any Go service that parses .xlsx files supplied by users or other untrusted sources with Excelize and calls GetStyle is exposed to a crash. Programs that only write spreadsheets they generate, or that handle only trusted files, are unlikely to be affected. unknown whether other Excelize functions are affected.
Not affected if no-untrusted-xlsx, trusted-input-only
Who cares cwe-129, cwe-20, excelize, go, spreadsheet-parsing
github.com/xuri/excelize/v2 in go.mod or with go list -m github.com/xuri/excelize/v2Upgrade to 2.11.1-0.20260731010303-ae2113b410e5
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.
styles.go, in GetStyle, lines 1683, 1686 and 1689:
xf := s.CellXfs.Xf[idx]
extractStyleCondFuncs[](xf, s) {
f.extractFills(s.Fills.Fill[*xf.FillID], s, style)
}
extractStyleCondFuncs[](xf, s) {
f.extractBorders(s.Borders.Border[*xf.BorderID], s, style)
}
extractStyleCondFuncs[](xf, s) {
style.Font = extractFont(s.Fonts.Font[*xf.FontID])
}
Are you affected?
Tell InfraStack what you run. It checks this one, and every next one, against your stack.
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
github.com/xuri/excelize/v2 2.11.1-0.20260731010303-ae2113b410e5The conditions, at lines 1171 to 1185, bound only the top:
"fill": func(xf xlsxXf, s *xlsxStyleSheet) bool {
return (xf.ApplyFill == nil || (xf.ApplyFill != nil && *xf.ApplyFill)) &&
xf.FillID != nil && s.Fills != nil &&
*xf.FillID < len(s.Fills.Fill)
},
*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 same function, six lines above at 1677:
if idx < 0 || s.CellXfs == nil || len(s.CellXfs.Xf) <= idx {
return style, newInvalidStyleID(idx)
}
and again at 1783. So the style index itself is guarded on both sides while the three ids it leads to are not.
Executed against master at f98df08, which is the merge of #2366, so this is current rather than historical. The harness builds a normal styled workbook with excelize, rewrites one attribute of the cellXfs entry inside the zip to -1, reopens it and calls GetCellStyle then GetStyle:
control (all >= 0) ok style=true err=<nil>
fillId=-1 PANIC: runtime error: index out of range [-1]
borderId=-1 PANIC: runtime error: index out of range [-1]
fontId=-1 PANIC: runtime error: index out of range [-1]
The control confirms the harness reads a valid file correctly, so the three panics are the negative ids rather than a broken fixture. Worth mentioning because my first attempt at this harness patched only fillId and appeared to show the other two were fine; they are not, the replacement had simply missed them.
Any application that opens an untrusted .xlsx and reads cell styling crashes. GetStyle is reached through GetCellStyle and from the style-copying and rendering paths, so it sits on the ordinary read path. With no recover() anywhere in excelize, a CLI or worker exits and a service returns 500 per request unless the caller installed its own recovery middleware.
No memory corruption and no information disclosure. Availability only.
Add the lower bound to each of the three conditions, matching what line 1677 already does for the style index:
*xf.FillID >= 0 && *xf.FillID < len(s.Fills.Fill)
and the same for BorderID and FontID. Three one-line changes in extractStyleCondFuncs.
This page as .md · .json · CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H
Go Vulnerability Database, CC-BY 4.0 · NVD data is provided by NIST and is public domain · GitHub Advisory Database, CC-BY 4.0. Posts quoted belong to their authors.