# CVE-2026-63267 — RCA: LFI and GET SSRF via calcext:data-mappings (csv provider)

## Summary

LibreOffice Calc persists external csv data-source links inside the document
(`calcext:data-mappings` / `calcext:data-mapping` with provider
`org.libreoffice.calc.csv`). In vulnerable versions the link target
(`xlink:href`) was fetched automatically while the document loaded, with no
link-update gate. Opening an attacker-crafted spreadsheet therefore (a) reads
an arbitrary local file into sheet cells (LFI, e.g. via `file:///etc/passwd`)
and (b) issues an attacker-directed HTTP GET to a host of the document's
choosing (SSRF). The reproduction proves both effects end-to-end through the
real LibreOffice Calc document-open path on LibreOffice 26.2.4.2, and proves
the negative control on fixed LibreOffice 26.2.5.2, where the fetch is gated
behind the same link-update control as other spreadsheet links.

## Impact

- Package/component: LibreOffice Calc (`sc`), external data providers
  (`calcext:data-mappings`, csv provider `org.libreoffice.calc.csv`).
- Affected versions: LibreOffice < 26.2.5 / < 26.8.0 (reproduced on
  26.2.4.2, build `0229ac93fcf0d7cbc6376066c6f35021cef002dc`).
- Risk: medium. Local file disclosure into the sheet (contents can then be
  exfiltrated, e.g. via a companion mapping or the sibling data-mapping bugs)
  and unauthenticated GET SSRF to arbitrary hosts (including internal network
  targets) triggered merely by opening a document.

## Impact Parity

- Disclosed/claimed maximum impact: local file read into the sheet (LFI) and
  attacker-directed GET request (SSRF) on document open.
- Reproduced impact from this run: both — the vulnerable build read a unique
  marker from a local `file://` CSV into cell A1 (2/2 attempts) and issued
  HTTP GETs carrying per-attempt unique tokens to the attacker-controlled
  server (2/2 attempts), both during plain document load.
- Parity: `full`.
- Not demonstrated: nothing claimed beyond LFI + GET SSRF; no code execution
  was claimed or pursued for this ticket.

## Root Cause

When a document containing `calcext:data-mappings` is loaded, Calc's external
data mapper (`ScExternalDataMapper`) reconstructs the persisted data sources
and the csv provider immediately refreshed (fetched) the mapping's
`xlink:href` target during load. Because the fetch happened at load time
rather than through the `sfx2::LinkManager` update path, neither the
"update links when loading" user setting nor any prompt protected the user:
the document decided if and where a fetch happened. Since `xlink:href`
accepts both `file://` and `http(s)://` URLs, the load-time fetch yields LFI
and SSRF respectively.

Fix: in LibreOffice 26.2.5 / 26.8.0 (fix by Caolán McNamara) a data mapping
loaded from a document is registered as an external link in the document's
`LinkManager`, and its data is only refreshed when link updating is allowed —
the same gate that governs sheet links and area links. The upstream QA test
`testLinkUpdateGate` (sc/qa/unit/dataproviders_test.cxx, fixture
`sc/qa/unit/data/dataprovider/mappinggate.fods`) encodes exactly this:
"With updating not allowed, updating the links leaves the saved value."

## Reproduction Steps

1. `bundle/repro/reproduction_steps.sh` (self-contained; downloads the
   official TDF release tarballs if not already cached under
   `bundle/artifacts/`).
2. The script:
   - Downloads and extracts LibreOffice 26.2.4.2 (vulnerable) and 26.2.5.2
     (fixed) Linux x86-64 deb packages (only `ure`, core, calc, en-us
     components) from downloadarchive.documentfoundation.org.
   - Generates a flat ODS (`.fods`) document whose
     `calcext:data-mapping` (provider `org.libreoffice.calc.csv`) points at
     `file://<workspace>/local_secret.csv` (LFI probe) and a second document
     pointing at `http://127.0.0.1:8931/CVE-2026-63267-SSRF-<token>.csv`
     (SSRF probe). The saved cell content is the sentinel
     `SAVED_SENTINEL_NOT_FETCHED`.
   - Starts a Python attacker HTTP server that logs every GET and serves a
     marker CSV.
   - Opens each document through the real product binary
     (`soffice --headless --convert-to csv`), 2 attempts per role
     (vuln/fixed × lfi/ssrf), each with an isolated user profile.
   - Evaluates: vulnerable LFI = converted sheet contains the local-file
     marker; vulnerable SSRF = attacker server received the per-attempt GET;
     fixed = sheet still holds the sentinel and no GET was received.
3. Expected evidence of reproduction: `sheet-vuln-lfi-*.csv` contain
   `CVE-2026-63267_LFI_SECRET_9f4d2c`; `http-server-final.log` contains GETs
   for the `vuln-ssrf-*` tokens only; `sheet-fixed-*.csv` contain
   `SAVED_SENTINEL_NOT_FETCHED`.

## Evidence

- Full run log: `bundle/logs/reproduction_steps.log` (two consecutive
  successful runs, both exit 0).
- Per-attempt product logs: `bundle/logs/{vuln,fixed}-{lfi,ssrf}-{1,2}.log`.
- Attacker server request log: `bundle/repro/http-server-final.log`:
  - `GET /CVE-2026-63267-SSRF-vuln-ssrf-1.csv from 127.0.0.1`
  - `GET /CVE-2026-63267-SSRF-vuln-ssrf-2.csv from 127.0.0.1`
  - No `fixed-ssrf-*` request lines.
- Converted sheets: `bundle/repro/sheet-vuln-lfi-1.csv` =
  `CVE-2026-63267_LFI_SECRET_9f4d2c` (local file content injected into the
  sheet at load); `bundle/repro/sheet-fixed-lfi-1.csv` =
  `SAVED_SENTINEL_NOT_FETCHED`.
- Verdict counts (both runs): vulnerable LFI 2/2, vulnerable SSRF 2/2,
  fixed LFI clean 2/2, fixed SSRF clean 2/2.
- Environment: Linux x86-64, no Docker; official TDF deb builds, headless
  `svp` VCL plugin. Vulnerable build identity: LibreOffice 26.2.4.2
  `0229ac93fcf0d7cbc6376066c6f35021cef002dc`, tarball SHA-256
  `810ef197e190d7804a60e0016052c46ff33792303a200fddda9d5216a64b9900`.
  Fixed build: LibreOffice 26.2.5.2 `cd7284b4cbbfeb507e630c1aac019f4157393acb`,
  tarball SHA-256 `2f03bfb2ac9f33ea7c77331b4b7a23300fb0ed7443566046bf8b5bc51c1bed1e`.
- Runtime manifest with artifact hashes:
  `bundle/repro/runtime_manifest.json`.

## Recommendations / Next Steps

- Upgrade to LibreOffice 26.2.5 / 26.8.0 or later, where external data links
  are updated only under the link-update control.
- The upstream fix approach (registering data mappings as LinkManager links
  gated by the link-update permission) is confirmed effective by the fixed
  negative control in this reproduction.
- Testing recommendation: keep `testLinkUpdateGate`-style coverage for both
  `file://` and `http(s)://` hrefs and for headless document load.

## Additional Notes

- Idempotency: the script was run twice consecutively in this session; both
  runs exited 0 with identical verdicts. Re-runs reuse the extracted builds
  under `bundle/artifacts/libreoffice/` and re-generate all documents,
  secrets, tokens, and logs.
- The demonstration uses the real product binary through its normal
  document-open path (`soffice --headless --convert-to csv`); no sanitizer,
  no mock, no reimplementation.
- The SSRF target is a loopback attacker server for safety; the vulnerable
  code path issues a real HTTP GET to whatever host the document names.
- Sibling data-mapping advisories (CVE-2026-63266 … CVE-2026-63277) share the
  same load-time fetch root cause with different providers/impacts; they are
  separate tickets.
