CVE-2026-23535: Verified Repro With Script Download
CVE-2026-23535: wlc: Path traversal via unsanitized API slugs in download command
CVE-2026-23535 is verified against wlc · pip. Affected versions: wlc < 1.17.2. Fixed in wlc 1.17.2. Vulnerability class: Path Traversal. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00070.
What Is CVE-2026-23535?
CVE-2026-23535 is a high-severity path traversal in the Weblate command-line client (wlc) before 1.17.2. A malicious Weblate server can make the client write files to an arbitrary location during a multi-translation download. Pruva reproduced it (reproduction REPRO-2026-00070).
CVE-2026-23535 Severity & CVSS Score
CVE-2026-23535 is rated high severity, with a CVSS base score of 8.0 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
Affected wlc Versions
wlc · pip versions wlc < 1.17.2 are affected.
How to Reproduce CVE-2026-23535
pruva-verify REPRO-2026-00070 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00070/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-23535
Reproduced by Pruva's autonomous agents — 216 tool calls over 21 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2026-23535
Summary
A malicious Weblate server can abuse the wlc download command’s multi-component workflow to write files outside the caller’s chosen output directory. The client trusts component metadata returned by the server and uses the embedded project slug verbatim when constructing the zip filename, allowing absolute paths to be honored and causing arbitrary file writes on the filesystem running wlc < 1.17.2.
Impact
- Package: Weblate
wlcCLI - Affected versions: All releases prior to 1.17.2
- Risk: High – a crafted server (or MITM) can force the client to overwrite arbitrary files (e.g.,
/etc/cron.d/...) duringwlc download --multi, leading to privilege escalation or system compromise on any machine that runs the command.
Root Cause
wlc.main.Download.download_component() builds the destination path as Path(output_dir) / f"{component.project.slug}-{component.slug}.zip". The values component.project.slug and component.slug come directly from API responses without sanitization. When a malicious server returns an absolute path such as /tmp/weblate-owned for the project slug, pathlib.Path treats it as an absolute path and drops the intended base directory, writing the downloaded archive to that attacker-chosen location. The issue is fixed upstream in https://github.com/WeblateOrg/wlc/pull/1128 (released in 1.17.2) which normalizes and validates slugs before using them in filesystem paths.
Reproduction Steps
- Run
repro/reproduction_steps.sh. - The script provisions a Python venv, installs
wlc==1.17.1, starts a mock Weblate HTTP server that serves a component listing whose project slug is/tmp/weblate-owned, and then executeswlc download --output repro-outputagainst it. - Successful reproduction is indicated by creation of
/tmp/weblate-owned-absolute-component.zip(outside the requested output directory) and logs stored inlogs/.
Evidence
- Log artifacts:
logs/mock_server.log,logs/wlc_download.log,logs/evidence.txt. - Key excerpt (
logs/evidence.txt):-rw-r--r-- 1 root root 58 ... /tmp/weblate-owned-absolute-component.zip- Intended output directory
repro-output/remains empty, proving the write escaped the sandbox.
- Environment: Python 3.11 virtualenv with
wlc==1.17.1on Ubuntu (container) as provisioned by the script.
Recommendations / Next Steps
- Upgrade
wlcclients to 1.17.2 or later, which sanitizes slugs before constructing output paths. - For additional defense-in-depth, consider enforcing a jail by resolving all download outputs relative to the configured directory and rejecting absolute inputs from the server.
- Add regression tests that simulate malicious slugs to ensure future changes preserve the validation.
Additional Notes
repro/reproduction_steps.shis idempotent: running it twice in succession succeeds, recreating the evidence and overwriting the malicious file each time.- The mock server only implements the minimal endpoints needed for this PoC; real-world instances may require authentication, but the vulnerability manifests regardless once the client processes attacker-controlled component metadata.
CVE-2026-23535 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.
Unknown error
cd /root/.pruva/runs/ghsa-mmwx-79f6-67jg_20260117-214540 && python3 -m venv venv && /root/.pruva/runs/ghsa-mmwx-79f6-67jg_20260117-214540/venv/bin/pip install --upgrade pip setuptools wheelRequirement already satisfied: pip in ./venv/lib/python3.11/site-packages (24.0) Collecting pip Using cached pip-25.3-py3-none-any.whl.metadata (4.7 kB) Requirement already satisfied: setuptools in ./venv/lib/python3.11/site-packages (79.0.1) Collecting setuptools Using cached setuptools-80.9.0-py3-none-any.whl.metadata (6.6 kB) Collecting wheel Using cached wheel-0.45.1-py3-none-any.whl.metadata (2.3 kB)
Artifacts and Evidence for CVE-2026-23535
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-23535
Upgrade wlc · pip to wlc 1.17.2 or later.
FAQ: CVE-2026-23535
What has to happen to exploit CVE-2026-23535?
Which versions of wlc are affected by CVE-2026-23535, and where is it fixed?
How can I reproduce CVE-2026-23535?
References for CVE-2026-23535
Authoritative sources for CVE-2026-23535 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.