Skip to content

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

  1. 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-src enumerate data:/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.
  2. 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: read src-tauri/capabilities/*.json for the remote-URL scope, check withGlobalTauri, then enumerate the app's own commands from generate_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.
  3. 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.
  4. 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.urls against 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.

  1. CSP verdict: dump the app's effective CSP (devtools or app source); grep script-src for data:/blob:. If present, prove the nonce is inert with a data:-URI or blob: script that flips an inert DOM marker — marker change = XSS-to-exec without nonce knowledge.
  2. 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.
  3. 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).
  4. Template diff: for generated apps (Pake-style), diff the shipped capabilities/default.json + tauri.conf.json against 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.