CVE-2026-107214
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks
Excelize is a Go language library for reading and writing Microsoft Excel spreadsheets. From 2.3.1 to 2.11.0, the decryption dispatch performs insufficient structural and parameter validation before standard and agile decryptors slice, index, allocate, and divide using attacker-controlled values. Decrypt passes attacker-controlled EncryptionInfo and EncryptedPackage data into standardDecrypt or agileDecrypt before validating the structures used by those routines. When a malformed OLE compound file with a version-valid EncryptionInfo stream is opened or passed to Decrypt, nine malformed-input classes reach unrecovered Go runtime panics instead of the documented error path, allowing an attacker to terminate the calling process. No fixed version is available as of this review.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks
Excelize is a Go language library for reading and writing Microsoft Excel spreadsheets. From 2.3.1 to 2.11.0, the decryption dispatch performs insufficient structural and parameter validation before standard and agile decryptors slice, index, allocate, and divide using attacker-controlled values. Decrypt passes attacker-controlled EncryptionInfo and EncryptedPackage data into standardDecrypt or agileDecrypt before validating the structures used by those routines. When a malformed OLE compound file with a version-valid EncryptionInfo stream is opened or passed to Decrypt, nine malformed-input classes reach unrecovered Go runtime panics instead of the documented error path, allowing an attacker to terminate the calling process. No fixed version is available as of this review.
- Record
CVE-2026-107214- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
EUVDEUVD-2026-94531
7.5
Excelize is a Go language library for reading and writing Microsoft Excel spreadsheets. From 2.3.1 to 2.11.0, the decryption dispatch performs insufficient structural and parameter validation before standard and agile decryptors slice, index, allocate, and divide using attacker-controlled values. Decrypt passes attacker-controlled EncryptionInfo and EncryptedPackage data into standardDecrypt or agileDecrypt before validating the structures used by those routines. When a malformed OLE compound file with a version-valid EncryptionInfo stream is opened or passed to Decrypt, nine malformed-input classes reach unrecovered Go runtime panics instead of the documented error path, allowing an attacker to terminate the calling process. No fixed version is available as of this review.
- Record
EUVD-2026-94531- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-2j4c-ffch-9f23
7.5
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks
Summary
Any file whose first 8 bytes are the OLE compound-file signature (D0 CF 11 E0 A1 B1 1A E1) is routed by OpenFile/OpenReader/OpenBytes → openReaderAt → Decrypt. The version dispatch only guarantees len(EncryptionInfo) >= 4 before handing attacker-controlled EncryptionInfo/EncryptedPackage buffers to standardDecrypt/agileDecrypt, and no callee validates structure. Malformed but version-valid content therefore fails as an unrecovered runtime panic instead of an error, terminating the calling process.
Details
All panic classes below were execution-confirmed against pristine master (ecd99d761fe0, 2026-09-08). excelize.go:211-213 maps Decrypt errors to ErrWorkbookFileFormat, but panics bypass that path and kill the process.
| # | Malformed input | Panic | Site |
|---|---|---|---|
| 1 | standard, len(EncryptionInfo) 4–11 | slice bounds [:12] | crypt.go:238 |
| 2 | standard, attacker-controlled headerSize uint32 | slice bounds [12:12+headerSize] / fixed-offset header reads | crypt.go:238-249 |
| 3 | standard, verifier remainder < 72 (AES) / 60 (RC4) bytes | slice bounds in standardEncryptionVerifier | crypt.go:282-295 |
| 4 | standard, header.KeySize = 0xFFFFFFFF | slice bounds [:536870911] with capacity 48 | crypt.go:321 |
| 5 | standard, EncryptedPackage stream missing/short | slice bounds [8:0] | crypt.go:268 |
| 6 | agile, len(EncryptionInfo) 4–7 | slice bounds [8:4] | crypt.go:407 |
| 7 | agile, valid XML without <keyEncryptors> | index out of range [0] with length 0 | crypt.go:416, 433 |
| 8 | agile, saltValue decoded length ≠ AES block | cipher.NewCBCDecrypter: IV length must equal block size | crypt.go:425 → 512 |
| 9 | any, keyData blockSize="0" | integer divide by zero | crypt.go:539 |
Note the asymmetry pinpointing the missing constraint: the agile path already checks len(EncryptedPackage) >= 8 (crypt.go:520-523) but the standard path does not (#5). Existing tests only cover the error paths (short <4 bytes → ErrUnknownEncryptMechanism, bad XML, base64 errors), never these panic paths.
PoC
Standalone programs (public API only, inputs built in memory) were provided to the maintainer by email: 1-decrypt-panic builds seven malformed CFB containers and shows each panic escaping the public Decrypt API plus one end-to-end OpenReader crash. All cases print PANIC on master and BLOCKED with the proposed patch. A regression guard proves legitimate decryption is unaffected: a workbook encrypted with the package's own Encrypt() still opens through the same code path.
(A separate advisory covers the unbounded/negative allocation in extractPart.)
Impact
Any service that calls OpenFile/OpenReader/OpenBytes on untrusted input (upload processing, mail scanning, spreadsheet conversion) can be killed remotely and without authentication by a file of ~100 bytes to ~3 KB. No password is required — panics occur during structural/parameter handling before successful decryption. Site variety means filtering one pattern does not help.
Proposed fix
A recover() boundary in Decrypt mapping any panic to ErrWorkbookFileFormat (restores the documented error-routing contract; legitimate standard/agile decryption unaffected). A complete patch has been provided to the maintainer; per-site length validation is recommended as defense in depth.
- Record
GHSA-2j4c-ffch-9f23- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
NVD
7.5
Excelize is a Go language library for reading and writing Microsoft Excel spreadsheets. From 2.3.1 to 2.11.0, the decryption dispatch performs insufficient structural and parameter validation before standard and agile decryptors slice, index, allocate, and divide using attacker-controlled values. Decrypt passes attacker-controlled EncryptionInfo and EncryptedPackage data into standardDecrypt or agileDecrypt before validating the structures used by those routines. When a malformed OLE compound file with a version-valid EncryptionInfo stream is opened or passed to Decrypt, nine malformed-input classes reach unrecovered Go runtime panics instead of the documented error path, allowing an attacker to terminate the calling process. No fixed version is available as of this review.
- Record
CVE-2026-107214- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
OSV
7.5
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks
Excelize is a Go language library for reading and writing Microsoft Excel spreadsheets. From 2.3.1 to 2.11.0, the decryption dispatch performs insufficient structural and parameter validation before standard and agile decryptors slice, index, allocate, and divide using attacker-controlled values. Decrypt passes attacker-controlled EncryptionInfo and EncryptedPackage data into standardDecrypt or agileDecrypt before validating the structures used by those routines. When a malformed OLE compound file with a version-valid EncryptionInfo stream is opened or passed to Decrypt, nine malformed-input classes reach unrecovered Go runtime panics instead of the documented error path, allowing an attacker to terminate the calling process. No fixed version is available as of this review.
- Record
CVE-2026-107214- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
OSVGHSA-2j4c-ffch-9f23
7.5
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks
Summary
Any file whose first 8 bytes are the OLE compound-file signature (D0 CF 11 E0 A1 B1 1A E1) is routed by OpenFile/OpenReader/OpenBytes → openReaderAt → Decrypt. The version dispatch only guarantees len(EncryptionInfo) >= 4 before handing attacker-controlled EncryptionInfo/EncryptedPackage buffers to standardDecrypt/agileDecrypt, and no callee validates structure. Malformed but version-valid content therefore fails as an unrecovered runtime panic instead of an error, terminating the calling process.
Details
All panic classes below were execution-confirmed against pristine master (ecd99d761fe0, 2026-09-08). excelize.go:211-213 maps Decrypt errors to ErrWorkbookFileFormat, but panics bypass that path and kill the process.
| # | Malformed input | Panic | Site |
|---|---|---|---|
| 1 | standard, len(EncryptionInfo) 4–11 | slice bounds [:12] | crypt.go:238 |
| 2 | standard, attacker-controlled headerSize uint32 | slice bounds [12:12+headerSize] / fixed-offset header reads | crypt.go:238-249 |
| 3 | standard, verifier remainder < 72 (AES) / 60 (RC4) bytes | slice bounds in standardEncryptionVerifier | crypt.go:282-295 |
| 4 | standard, header.KeySize = 0xFFFFFFFF | slice bounds [:536870911] with capacity 48 | crypt.go:321 |
| 5 | standard, EncryptedPackage stream missing/short | slice bounds [8:0] | crypt.go:268 |
| 6 | agile, len(EncryptionInfo) 4–7 | slice bounds [8:4] | crypt.go:407 |
| 7 | agile, valid XML without <keyEncryptors> | index out of range [0] with length 0 | crypt.go:416, 433 |
| 8 | agile, saltValue decoded length ≠ AES block | cipher.NewCBCDecrypter: IV length must equal block size | crypt.go:425 → 512 |
| 9 | any, keyData blockSize="0" | integer divide by zero | crypt.go:539 |
Note the asymmetry pinpointing the missing constraint: the agile path already checks len(EncryptedPackage) >= 8 (crypt.go:520-523) but the standard path does not (#5). Existing tests only cover the error paths (short <4 bytes → ErrUnknownEncryptMechanism, bad XML, base64 errors), never these panic paths.
PoC
Standalone programs (public API only, inputs built in memory) were provided to the maintainer by email: 1-decrypt-panic builds seven malformed CFB containers and shows each panic escaping the public Decrypt API plus one end-to-end OpenReader crash. All cases print PANIC on master and BLOCKED with the proposed patch. A regression guard proves legitimate decryption is unaffected: a workbook encrypted with the package's own Encrypt() still opens through the same code path.
(A separate advisory covers the unbounded/negative allocation in extractPart.)
Impact
Any service that calls OpenFile/OpenReader/OpenBytes on untrusted input (upload processing, mail scanning, spreadsheet conversion) can be killed remotely and without authentication by a file of ~100 bytes to ~3 KB. No password is required — panics occur during structural/parameter handling before successful decryption. Site variety means filtering one pattern does not help.
Proposed fix
A recover() boundary in Decrypt mapping any panic to ErrWorkbookFileFormat (restores the documented error-routing contract; legitimate standard/agile decryption unaffected). A complete patch has been provided to the maintainer; per-site length validation is recommended as defense in depth.
- Record
GHSA-2j4c-ffch-9f23- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-248
- Updated
- 2026-11-02
OSVGO-2026-6684 No score
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks in github.com/xuri/excelize
Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks in github.com/xuri/excelize
- Record
GO-2026-6684- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/xuri/excelize/v2Go |
2.3.1 up to 2.11.1-0.20260915055537-22f76f9acb94 | 2.11.1-0.20260915055537-22f76f9acb94 |
github.com/360EntSecGroup-Skylar/excelize/v2Go |
2.3.1 and later | None known |
github.com/xuri/excelize/v2Go |
before 2.11.1-0.20260915055537-22f76f9acb94 | 2.11.1-0.20260915055537-22f76f9acb94 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-107214 is a high vulnerability (CVSS 7.5) in Excelize, published October 7, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.24%, the 15th percentile. Fixed in github.com/xuri/excelize/v2 2.11.1-0.20260915055537-22f76f9acb94.
References
github.com/qax-os/excelize/security/advisories/GHSA-2j4c-ffch-9f23
github.com/qax-os/excelize/pull/2395
github.com/qax-os/excelize/commit/22f76f9acb94b85b3eb9c4365ab4f750cebbc565
nvd.nist.gov/vuln/detail/CVE-2026-107214
github.com/advisories/GHSA-2j4c-ffch-9f23
github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107214.json
github.com/qax-os/excelize