{"schema":"threatline.record/2","record":{"id":"CVE-2026-107216","aliases":["GHSA-wp2g-vpjj-g53r","GO-2026-6688"],"summary":"Excelize ANCHORARRAY: mutually-referencing array formulas recurse unboundedly via re-entrant CalcCellValue, causing a fatal stack overflow","details":"### Summary\n\n`ANCHORARRAY` (calc.go:15137 on current master) evaluates each cell of the referenced spill range by calling the **exported** `CalcCellValue`, which unconditionally constructs a fresh `calcContext` — fresh entry marker, fresh iterations map, full `MaxCalcIterations` budget (calc.go:896-900). The circular-reference control only exists **within one context**: the entry-exclusion marker and per-ref iteration budget are fields of that single context, and completion-based caching (`formulaArgCache`/`calcRawCache`) only ever stores results of evaluations that *finish*.\n\nDuring a pure cycle no nested evaluation ever finishes, so nothing is ever cached to break the recursion, and each hop re-arms the entire budget. Two ordinary, Excel-legal constructs in an attacker-supplied workbook are enough:\n\n- `A1` (dynamic array formula, ref `A1:A1`): `_xlfn.ANCHORARRAY($B$1)`\n- `B1` (dynamic array formula, ref `B1:B1`): `_xlfn.ANCHORARRAY($A$1)`\n\n→ `CalcCellValue → calcCellValue → evalInfixExp → parseReference → cellResolver → … → ANCHORARRAY → CalcCellValue → …` forever, ending in a **fatal, unrecoverable** Go runtime error: `runtime: goroutine stack exceeds …-byte limit / fatal error: stack overflow`. Go stack overflows cannot be recovered — the whole process aborts.\n\n### Details\n\n- The terminating edge the iterations gate is supposed to provide does not exist across contexts: there is no in-flight tracking shared between nested `CalcCellValue` calls.\n- Both formulas are ordinary Excel-legal constructs; no exotic XML is required.\n- Excelize's own APIs reach formula evaluation on untrusted cells implicitly (e.g. `pivotTable.go:538`, `picture.go:985/1141`, `col.go:892`), so a service that merely adds a pivot table or a picture over such a workbook dies.\n- No option value prevents it: `MaxCalcIterations` is irrelevant because every hop gets a fresh budget.\n- Measured: a 64 MB stack budget is exhausted in ~0.09 s; the ~1 GB default in ~1–2 s.\n\n### PoC\n\nA standalone program (public API only) was provided to the maintainer by email (`4-anchorarray-recursion`): `NewFile` + `SetCellFormula` with `FormulaOpts{Type: array, Ref: A1:A1 / B1:B1}`, then `CalcCellValue(\"Sheet1\",\"A1\")`. On master `ecd99d761fe0` (2026-09-08) the process aborts with `fatal error: stack overflow`; with the proposed patch the cycle terminates normally (`CYCLE_TERMINATED`) and existing calc tests pass.\n\n### Impact\n\nAn attacker ships a workbook containing the two formulas; any service that evaluates a formula over those cells — directly via `CalcCellValue`, or implicitly via `AddPivotTable` / `AddPicture` / auto-fit — aborts. Remote, unauthenticated, process-fatal, no configuration prevents it.\n\n### Proposed fix\n\nEvaluate spill-range cells through the **current** calculation context — `fn.f.cellResolver(fn.ctx, …)` instead of the exported `CalcCellValue` — so the entry check and iterations gate of the running calculation apply. `cellResolver` returns the typed value directly (dropping a string round-trip); an `ArgEmpty → \"\"` shim preserves the existing `ToNumber` behavior for empty spill cells, and a fresh-context fallback covers the legacy nil-ctx test paths. A complete patch has been provided to the maintainer.","categories":["Libraries & packages"],"product":"github.com/xuri/excelize/v2","vendor":"qax-os","ecosystem":"go","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-wp2g-vpjj-g53r","source_modified_at":"2026-10-08T16:31:23Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/xuri/excelize/v2"},"range":">= 2.8.1, < 2.11.1-0.20260911060113-ea12859e43c6"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107216","source_modified_at":"2026-10-07T18:51:04.748Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"excelize","vendor":"qax-os","versions":[{"version":">= 2.8.1, <= 2.11.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-wp2g-vpjj-g53r","source_modified_at":"2026-10-19T21:41:18.715896320Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"github.com/xuri/excelize/v2","ecosystem":"Go","purl":"pkg:golang/github.com/xuri/excelize/v2"},"ranges":[{"type":"SEMVER","events":[{"introduced":"2.8.1"},{"fixed":"2.11.1-0.20260911060113-ea12859e43c6"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-wp2g-vpjj-g53r","source_modified_at":"2026-10-08T16:31:23Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"go","name":"github.com/xuri/excelize/v2"},"version":"2.11.1-0.20260911060113-ea12859e43c6"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-wp2g-vpjj-g53r","source_modified_at":"2026-10-19T21:41:18.715896320Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"github.com/xuri/excelize/v2","ecosystem":"Go","purl":"pkg:golang/github.com/xuri/excelize/v2"},"version":"2.11.1-0.20260911060113-ea12859e43c6"}],"cvss":7.5,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00329,"percentile":0.24846,"score_date":"2026-10-23"},"published_at":"2026-10-07T17:51:31.980Z","modified_at":"2026-10-19T21:41:18.715896320Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-wp2g-vpjj-g53r","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-08T16:31:23Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107216","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-07T18:51:04.748Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-wp2g-vpjj-g53r","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-19T21:41:18.715896320Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107216","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/qax-os/excelize/security/advisories/GHSA-wp2g-vpjj-g53r","tags":["x_refsource_CONFIRM"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-107216","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/qax-os/excelize/commit/ea12859e43c64d498ecf839263c5f917391f3316","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-wp2g-vpjj-g53r","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"yes","technical_impact":"partial","assessed_at":"2026-10-07T18:50:55.568606Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-19T21:41:18.715896320Z","content_hash":"5d6ae0f3a3521492ce32bbdbf0a6888f5d48fb65dedfdff812f98fc2ff291bc3"}}
