
Element Desktop v1.12.29 - High - Local - File - vector: protocol reads Windows files outside the asar jail
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · element-vector-drive-letter
Element Desktop v1.12.29 - Element Creations Ltd
Class: File read Reach: Local
apps/desktop/src/electron-main.ts registers vector: as a privileged file protocol. The jail is only relTarget.startsWith("..") after path.normalize(path.join(...pathname.split("/").slice(2))). On Windows a join of C:, Windows, win.ini is already C:\Windows\win.ini. Absolute paths do not start with .., so the check lets them through. Electron's own custom-protocol note also rejects path.isAbsolute. POSIX path.join does not treat C: as absolute, so Linux and macOS are not this leftover. will-navigate allows vector: through.
Renderer XSS, DevTools, or another local process can fetch("vector://vector/webapp/C:/Windows/win.ini") and read files the Element process can open.
| ID | no CVE yet |
| CWE | CWE-22 / CWE-73 |
| CVSS | High: 8.3 CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N |
| Product | element-web Desktop (apps/desktop) |
| Affected | v1.12.29 (2d90d6b7b601ecb9ccdf81239a43b4396b4b0c9e). Windows only. |
| Auth | local renderer (DevTools / XSS) |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Renderer XSS, DevTools, or another local process that can hit vector:. Native Windows Element Desktop was not run. The gadget copies the pin's URL parser and uses Node path.win32.
| Privilege | Method / sink | Recon / integrity / availability | Lab-proven or inferred |
|---|---|---|---|
| Read a file the Element process can open | fetch("vector://vector/webapp/C:/Windows/win.ini"). Jail is only relTarget.startsWith(".."). Drive-letter join is absolute, so the check passes. path.win32.resolve(asar, relTarget) is C:\Windows\win.ini | Recon | Lab-proven on the URL-parser gadget. Body is ELEMENT-VECTOR-DRIVE-LETTER-WITNESS. Native Desktop not run |
Same read of electron-config, profiles, other users' files on the same ACL | Same vector://vector/webapp/C:/... fetch | Recon | Inferred. Lab planted win.ini, not live secrets |
| Matrix ATO if the main frame loads attacker HTML already on disk | will-navigate lets vector: through. Hostile HTML at vector://vector gets preload / window.electron (tokens, Seshat, clearStorage) | Integrity | Inferred from webcontents-handler.ts and preload. Lab did not navigate a BrowserWindow |
../ traversal of the asar tree | vector://vector/webapp/../ | n/a | Closed here. WHATWG URL collapses it; handler returns FILE_NOT_FOUND (-6) |
| POSIX / macOS / Linux drive-letter fetch | path.posix.join leaves C:/Windows/win.ini under asar | n/a | Closed here. Gadget posix 404, no witness |
| OS RCE / LPE | nodeIntegration: false, app.enableSandbox() | n/a | Closed. Not this leftover |
Same pin leftovers: fragment guest wipe, Univention ICS javascript: href.
I pinned element-hq/element-web v1.12.29 after the 22 Sep 2026 GitHub release. Timeline XSS, HTML-export XSS (GHSA-wqmv), homepage HTML (GHSA-wrcp), widget media token (GHSA-3jm3), and Element Call keys (GHSA-69q3) are closed on this tag. The Desktop custom protocol still only checks startsWith("..").
new URL("vector://vector/webapp/C:/Windows/win.ini") keeps C: as a path segment. path.win32.join("C:", "Windows", "win.ini") is C:\Windows\win.ini. Node path.win32.join(asar, abs) concatenates; path.win32.resolve drops the asar root.
Wrong turns already recorded: treating ../ as the leftover (WHATWG collapses it, handler 404s); calling POSIX C: the same bug (posix join stays under asar); inflating file read to OS RCE (sandbox and nodeIntegration: false stay on). A reverse shell. Theatre.
Gadget of the URL parser. Node path.win32 vs path.posix. No Windows Element Desktop process. Planted /lab/oracle/win.ini stands in for C:\Windows\win.ini. /lab/asar/index.html is the asar jail.
python3 element-vector-drive-letter-Abraxas-Labs.py
or
cd lab
./run.sh
Target only http://127.0.0.1:19610. Compose project element-vector-drive-letter. Stack tears down after the run.
SUCCESS element-vector-drive-letter how=gadget win32-drive-letter=200 posix-drive-letter=404 control-dotdot=404 patched-isabs=404 ELEMENT-VECTOR-DRIVE-LETTER-WITNESS
After normalize, reject path.isAbsolute(relTarget) and require path.resolve(baseDir, relTarget) to stay under path.resolve(baseDir) (path.relative, refuse ..).
electron-main.ts (registerFileProtocol)webcontents-handler.ts (will-navigate)GNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.