Tauri desktop IPC, CSP, and scope-escalation cluster — the webview is the supply chain (Sept 23)¶
Source: hourly offensive-security scan, 2026-09-23. GitHub advisories GHSA-757j-xrg3-9g6p / CVE-2026-95626 (Tauri CSP nonce hardening), GHSA-j8fp-v6pf-qx45 / CVE-2026-95627 (Tauri dialog plugin scope), GHSA-jwcr-mx7v-qwwq / CVE-2026-96454 (Pake generated apps).
Three advisories in one publication window expose the same structural fact about Tauri-based desktop applications: the framework's defenses (CSP nonce, capability ACL, user consent dialogs) each enforce a narrower property than developers believe, and the web content inside the window — including third-party scripts the wrapped page loads on its own — is inside the trust boundary the defenses were meant to guard. This is the desktop-side twin of the Sept 22 mcp-atlassian gate-coverage lesson: each gate enforces less than its name implies; audit the enforced property, not the gate's name.
Earlier Tauri items live on their own pages and stay canonical: updater unsigned-manifest downgrade (CVE-2026-95625, authenticate the descriptor not the payload) and the Foxit/OEM desktop-update cluster on the Sept 23 document-viewer page; webview-driven allowDowngrades and microsandbox argv leaks on the Aug 5 Electron/authority page.
The cluster¶
| GHSA / CVE | Boundary | What the defense actually enforces |
|---|---|---|
| GHSA-757j-xrg3-9g6p / CVE-2026-95626 | Tauri's CSP hardening injects a random nonce to restrict script execution — zero protection when the app's script-src also lists data: or blob: | A nonce restricts hostless script statements, not scheme-allowed script sources. Per CSP Level 3, scheme sources stay active even when a nonce is present. Any XSS in such an app executes arbitrary script without ever learning the nonce. |
| GHSA-j8fp-v6pf-qx45 / CVE-2026-95627 | Dialog plugin file/folder picker: an attacker with JS execution (XSS) can force the scope expansion to be recursive — one ordinary-looking click on the OS picker grants read/write over an entire directory tree, with no indication recursion was granted and no way to revoke it for the app's lifetime | The consent dialog proves the user clicked, not what was granted. Scope grants are silent-maximum and permanent per session. |
| GHSA-jwcr-mx7v-qwwq / CVE-2026-96454 | Pake (website → Tauri desktop app generator): every generated app inherits "remote": { "urls": ["https://*.*"] } in capabilities/default.json (IPC accepted from any HTTPS origin) plus "withGlobalTauri": true (window.__TAURI__.core.invoke() reachable from ordinary page JS). Tauri's ACL only checks plugin:-prefixed commands — app commands registered via generate_handler! are never ACL-checked, so any origin with IPC access calls every app command. Chained with the download_file path traversal (CVE-2026-82635) this is arbitrary file write from any web page | The capability ACL enforces plugin-command authorization only; the app's own native surface is unenforced. The remote-URL allowlist is the only boundary between the open web and native commands — and the template ships it wide open. |
Durable axes¶
- Nonce ≠ script lockdown; audit the CSP's scheme sources first. For any Tauri/Electron/CSP-hardened webview app, the first audit question is not "is there a nonce?" but "does
script-srcenumeratedata:/blob:/unsafe-eval?" If it does, the nonce is decoration and every reflected/stored XSS in the renderer is full code execution in the webview context. Same-shape siblings already canonical here: Svelte SSR attribute-spread key confusion, sanitize-then-rewrite quote defeat (Sept 22 GHES) — the defense composes wrong with the configuration, not wrong by itself. - The capability ACL is per-command-namespace, not per-native-capability. Pake's exploit works because
generate_handler!app commands bypass the ACL entirely. Audit rule for any Tauri app: readsrc-tauri/capabilities/*.jsonfor the remote-URL scope, checkwithGlobalTauri, then enumerate the app's own commands fromgenerate_handler!in the Rust source — those are unACLed native calls available to every origin the remote scope admits, which in generated/template apps means every HTTPS site. The advertising and analytics scripts a wrapped site loads are therefore inside the native-IPC attack surface: a compromised CDN the site embeds is a desktop-app exploit. - Consent-scope escalation: what the dialog says vs what the grant is. The dialog-picker recursion bug (95627) generalizes beyond Tauri: any "pick a folder/file" consent affordance whose resulting scope is computed from request-controlled parameters (recursive: true/false) grants silently-maximum access. Post-exploitation value: a single user click yields persistent recursive FS read/write for the session — treat it as desktop persistence, not a popup annoyance. Detection during authorized desktop engagements: after granting a file picker, probe whether the app can read/write siblings and subdirectories of the picked item.
- Webview supply chain: the wrapped site's third-party scripts are attackers-in-residence. Pake proves the template defaults ship that residence with native IPC. For any company distributing a Tauri wrapper of their web app, check the template's
remote.urlsagainst what the wrapped page actually loads (ads/analytics/CDN): every loaded origin is a candidate caller of the app's native commands.
Validation workflow (authorized scope only)¶
Own builds, own canaries
Run against Tauri apps you have permission to test — ideally built from their public templates in your own lab. Never pivot from a finding into a real user's filesystem; prove scope/IPC reach with marker files in a disposable directory you own.
- CSP verdict: dump the app's effective CSP (devtools or app source); grep
script-srcfordata:/blob:. If present, prove the nonce is inert with adata:-URI orblob:script that flips an inert DOM marker — marker change = XSS-to-exec without nonce knowledge. - ACL sweep: decompile/read the shipped binary or source for
generate_handler!command names; from a controlled page inside the app's webview (or a second HTTPS origin the remote scope admits, in your own lab build),invoke()each app command with canary arguments. Record which commands answer without any ACL prompt — that list is the report. - Scope recursion probe: grant a single-file picker, then attempt read/write of a sibling marker file and a child-directory marker. Acceptance with no further prompt is the finding (95627 shape).
- Template diff: for generated apps (Pake-style), diff the shipped
capabilities/default.json+tauri.conf.jsonagainst upstream template defaults — inherited-insecure-defaults (the lamp-cloud/anyone/and SxDevOps class) apply to desktop scaffolding too.
Reporting heuristics¶
- Headline sentence = the reachable set, not the misconfiguration: "any HTTPS page loaded in the app window — including the ads on the wrapped site — can call
<N>native commands, including arbitrary file write" beats "wildcard remote scope". - For CSP items, report the composition (nonce + scheme source = inert hardening), and cite the spec clause; vendors argue "we have CSP hardening enabled."
- Attach the enumerated unACLed app-command list and the recursion-grant transcript (grant click → sibling write accepted); these convert "audit finding" to "exploited chain".
- Note persistence/staleness: the recursive scope can't be revoked for the app lifetime — say so; it changes severity.
Tracked without publication (same wave)¶
- Emacs Flymake arbitrary code execution while syntax-checking an edited file (CVE-2026-96442 / GHSA-hmfx-447r-rwh3, <31.2) — user-interaction client-side exec class already tracked for Emacs (96269, read-symbol-shorthands); relevant only for authorized client-side/phish-sim campaigns.
- Apache Doris JDBC driver URL validation → FE RCE (CVE-2026-96443 / GHSA-h927-w38j-3g6x) — privileged-user precondition; JDBC-URL-as-outbound-driver-instantiation axis is adjacent to the JNDI family (GeoServer page); revisit if a detail-free → detailed follow-up lands. Doris FE unauth item 31377 already folded on the Sept 21 page today.
- Apache Sling Security Bundle pair + XSS XXE (94243 ReferrerFilter accepts weaker-than-origin evidence, 94251 ContentDispositionFilter mediates only one address/API shape, 92001 recursive-entity XXE in XSS lib) — the "filter covers one shape/alias of a resource" axis is canonical on this wiki (Keycloak versioned route families, alternate-name WebSocket bypass folded today on the Tomcat page); Sling detail is too sparse to add a new validation boundary.
- Qt / Qt Quick memory-safety singles (79616 SVG path OOB read, 78253 QXmlStreamReader recursion) — parser memory-safety class, tracked per precedent.
- WordPress singles: Forminator unauthenticated metadata-key injection incl. WP-reserved keys onto submitted posts (87071 — post-meta write axis canonical on the Sept 19 WP page, but this leg adds no new sink beyond it), Forminator forwarding-header trust before proxy check for vote limits/attribution (87070 — Aug 28 9router axis), Ninja Tables unauthenticated shortcode expansion via form entries in a non-default config (86612 — shortcode-execution-surface axis canonical Sept 19), Paid Membership Subscriptions reCAPTCHA skipped when the form field is absent (90950 — absent-field skip = the
if (present) verify()twin of the skip-condition rule on the Sept 23 payment page), GTranslate/WP Recipe Maker shortcode-strip singles, MPCX Lightbox unauth access-low. Paymob's third webhook leg (87978 signature not verified) is the same plugin already promoted on the Sept 23 payment-cluster page — processed there. - Microweber pair (5695 arbitrary file upload → code exec, 5696 reflected XSS) — CMS upload-family without sink detail (which handler/extension check failed); tracked, revisit if the fix diff lands.
Evidence and reporting boundaries¶
- All IPC/scope proofs use marker files inside directories you created; never demonstrate a file-scope bug by reading real user documents or SSH keys.
- Cross-origin IPC proofs use HTTPS endpoints you control (your own page, your own cert); never exploit a live third-party site's page to prove the origin reachability.
- XSS-for-execution proofs stop at an inert DOM marker; never exfiltrate, persist, or move laterally through a discovered webview→native channel.