{"id":"CVE-2026-107214","aliases":["EUVD-2026-94531","GHSA-2j4c-ffch-9f23","GO-2026-6684"],"status":"published","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks","description":"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.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.0024,"percentile":0.15293,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-248"],"published":"2026-10-07T17:45:14Z","modified":"2026-10-28T02:30:49Z","fixes":[{"ecosystem":"Go","package":"github.com/xuri/excelize/v2","fixed_in":["2.11.1-0.20260915055537-22f76f9acb94"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Go","package":"github.com/xuri/excelize/v2","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.3.1"},{"fixed":"2.11.1-0.20260915055537-22f76f9acb94"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/xuri/excelize/v2","ranges":[{"type":"SEMVER","events":[{"introduced":"2.3.1"},{"fixed":"2.11.1-0.20260915055537-22f76f9acb94"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/360EntSecGroup-Skylar/excelize/v2","ranges":[{"type":"SEMVER","events":[{"introduced":"2.3.1"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/xuri/excelize/v2","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.11.1-0.20260915055537-22f76f9acb94"}]}]}],"products":[{"vendor":"excelize","product":"excelize"},{"vendor":"qax-os","product":"excelize"}],"references":[{"url":"https://github.com/qax-os/excelize/security/advisories/GHSA-2j4c-ffch-9f23","tags":["x_refsource_CONFIRM","exploit","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/qax-os/excelize/pull/2395","tags":["x_refsource_MISC","Issue Tracking","Patch","fix","web"]},{"url":"https://github.com/qax-os/excelize/commit/22f76f9acb94b85b3eb9c4365ab4f750cebbc565","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-107214","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-2j4c-ffch-9f23"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/107xxx/CVE-2026-107214.json","tags":["advisory"]},{"url":"https://github.com/qax-os/excelize","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-107214","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks","description":"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.","status":"published","published":"2026-10-07T17:45:14.274Z","modified":"2026-10-07T19:46:20.891Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T13:45:14.072357Z"}],"euvd":[{"id":"EUVD-2026-94531","description":"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.","status":"published","published":"2026-10-07T17:45:14Z","modified":"2026-10-07T19:46:20Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T17:27:33.904651Z"}],"ghsa":[{"id":"GHSA-2j4c-ffch-9f23","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks","description":"### Summary\n\nAny 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) \u003e= 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.\n\n### Details\n\nAll 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.\n\n| # | Malformed input | Panic | Site |\n|---|---|---|---|\n| 1 | standard, `len(EncryptionInfo)` 4–11 | slice bounds `[:12]` | `crypt.go:238` |\n| 2 | standard, attacker-controlled `headerSize` uint32 | slice bounds `[12:12+headerSize]` / fixed-offset header reads | `crypt.go:238-249` |\n| 3 | standard, verifier remainder \u003c 72 (AES) / 60 (RC4) bytes | slice bounds in `standardEncryptionVerifier` | `crypt.go:282-295` |\n| 4 | standard, `header.KeySize` = 0xFFFFFFFF | slice bounds `[:536870911]` with capacity 48 | `crypt.go:321` |\n| 5 | standard, `EncryptedPackage` stream missing/short | slice bounds `[8:0]` | `crypt.go:268` |\n| 6 | agile, `len(EncryptionInfo)` 4–7 | slice bounds `[8:4]` | `crypt.go:407` |\n| 7 | agile, valid XML without `\u003ckeyEncryptors\u003e` | index out of range `[0]` with length 0 | `crypt.go:416`, `433` |\n| 8 | agile, `saltValue` decoded length ≠ AES block | `cipher.NewCBCDecrypter: IV length must equal block size` | `crypt.go:425` → `512` |\n| 9 | any, `keyData blockSize=\"0\"` | integer divide by zero | `crypt.go:539` |\n\nNote the asymmetry pinpointing the missing constraint: the agile path already checks `len(EncryptedPackage) \u003e= 8` (`crypt.go:520-523`) but the standard path does not (#5). Existing tests only cover the error paths (short `\u003c4` bytes → `ErrUnknownEncryptMechanism`, bad XML, base64 errors), never these panic paths.\n\n### PoC\n\nStandalone 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.\n\n(A separate advisory covers the unbounded/negative allocation in `extractPart`.)\n\n### Impact\n\nAny 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.\n\n### Proposed fix\n\nA `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.","status":"published","published":"2026-10-08T16:31:32Z","modified":"2026-10-08T16:31:32Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T14:41:29.107536Z"}],"nvd":[{"id":"CVE-2026-107214","description":"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.","status":"published","published":"2026-10-07T18:17:19.04Z","modified":"2026-10-13T14:24:00.23Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T14:12:54.809359Z"}],"osv":[{"id":"CVE-2026-107214","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks","description":"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.","status":"published","published":"2026-10-07T17:45:14.274Z","modified":"2026-10-28T02:30:49.860004318Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T15:44:54.933106Z"},{"id":"GHSA-2j4c-ffch-9f23","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks","description":"### Summary\n\nAny 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) \u003e= 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.\n\n### Details\n\nAll 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.\n\n| # | Malformed input | Panic | Site |\n|---|---|---|---|\n| 1 | standard, `len(EncryptionInfo)` 4–11 | slice bounds `[:12]` | `crypt.go:238` |\n| 2 | standard, attacker-controlled `headerSize` uint32 | slice bounds `[12:12+headerSize]` / fixed-offset header reads | `crypt.go:238-249` |\n| 3 | standard, verifier remainder \u003c 72 (AES) / 60 (RC4) bytes | slice bounds in `standardEncryptionVerifier` | `crypt.go:282-295` |\n| 4 | standard, `header.KeySize` = 0xFFFFFFFF | slice bounds `[:536870911]` with capacity 48 | `crypt.go:321` |\n| 5 | standard, `EncryptedPackage` stream missing/short | slice bounds `[8:0]` | `crypt.go:268` |\n| 6 | agile, `len(EncryptionInfo)` 4–7 | slice bounds `[8:4]` | `crypt.go:407` |\n| 7 | agile, valid XML without `\u003ckeyEncryptors\u003e` | index out of range `[0]` with length 0 | `crypt.go:416`, `433` |\n| 8 | agile, `saltValue` decoded length ≠ AES block | `cipher.NewCBCDecrypter: IV length must equal block size` | `crypt.go:425` → `512` |\n| 9 | any, `keyData blockSize=\"0\"` | integer divide by zero | `crypt.go:539` |\n\nNote the asymmetry pinpointing the missing constraint: the agile path already checks `len(EncryptedPackage) \u003e= 8` (`crypt.go:520-523`) but the standard path does not (#5). Existing tests only cover the error paths (short `\u003c4` bytes → `ErrUnknownEncryptMechanism`, bad XML, base64 errors), never these panic paths.\n\n### PoC\n\nStandalone 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.\n\n(A separate advisory covers the unbounded/negative allocation in `extractPart`.)\n\n### Impact\n\nAny 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.\n\n### Proposed fix\n\nA `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.","status":"published","published":"2026-10-08T16:31:32Z","modified":"2026-10-19T21:40:56.735377549Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-248"],"updated_at":"2026-11-02T15:46:34.338541Z"},{"id":"GO-2026-6684","title":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks in github.com/xuri/excelize","description":"Excelize Decrypt: unrecoverable panics on malformed OLE/CFB encrypted workbooks in github.com/xuri/excelize","status":"published","published":"2026-10-19T21:08:21Z","modified":"2026-10-19T21:31:35.702899949Z","updated_at":"2026-11-02T15:47:03.11707Z"}]}}
