Build1 publisher3 min readPublished
WorldScript Studio's Tauri desktop build stores projects without the PWA's at-rest encryption
WorldScript Studio says its passphrase encryption covers PWA data in IndexedDB but not its Tauri desktop app's filesystem project store. The same React/Vite code runs in both, so the storage path decides what a user's encryption setting actually protects.
The Engineer · Build desk

What happened
- A fetch adapter loads Tauri's native HTTP plugin inside the desktop runtime and falls back to the browser's fetch everywhere else.
- On GitHub Pages a meta Content Security Policy is the only enforcement point, because that host cannot set the matching response headers.
- Vercel and Cloudflare Pages send real CSP headers, and each runs a same-origin Claude proxy built from one shared core module.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure Anyone with read access to the desktop app's application-data folder can read project files that the PWA would have kept encrypted at rest.
- exposure The port wildcard puts every HTTP service listening on loopback within reach of the desktop app's native plugin, a boundary the browser build gets from CORS and Private Network Access.
- decision Picking GitHub Pages over Vercel or Cloudflare Pages for the web build means accepting a meta tag as the only CSP enforcement and going without the same-origin Claude relay.
The encryption is tied to a storage API, and each shell picks its own. In WorldScript Studio, the PWA's live project path writes to browser storage. The desktop build writes filesystem-backed stores under application data [3]. The passphrase-based encryption lifecycle covers protected IndexedDB data when a user configures it [5]. The desktop project store does not currently get that at-rest encryption [5]. Both builds come from one React/Vite codebase [1], so the settings screen can match while the files on disk do not. "A UI toggle with the same name is not enough to make the protection equivalent," the project's write-up says [6].
The two stores answer to different rules as well. Browser persistence is bounded by origin, quota, eviction and the storage APIs. Desktop persistence is bounded by filesystem access, native process boundaries and the application's own read/write rules [4].
Networking splits along the same line. A browser tab calling localhost is still subject to CORS and Private Network Access [7]. The Tauri shell uses a native HTTP capability declared in `src-tauri/capabilities/default.json` [8]. Its remote entries are named hosts, `generativelanguage.googleapis.com` and `api.openai.com` among them, and the excerpt's comment ends with "remaining provider hosts, nothing else" [8]. A config comment that states its own limit is a small thing, and I'd like to see it in more capability files. The loopback entries, `http://localhost:*/*` and `http://127.0.0.1:*/*`, carry a port wildcard. The native plugin can therefore reach any HTTP service listening on loopback [15]. The desktop-native path is how the app supports Ollama-compatible local inference servers [10]. The write-up is plain about the cost: "That does not mean desktop networking is automatically safer." [14]
The switch between the two policies is small. The fetch adapter checks its environment, dynamically loads the native HTTP plugin inside the Tauri runtime, and uses the browser's `fetch` everywhere else [9]. The project states the rule behind it: "Share domain semantics and interoperability contracts. Expose platform capabilities through explicit adapters." [13] I think this is the right split for an app that talks to both cloud and local model endpoints. Callers see one function. On desktop the policy sits in the capability file. On the web it sits in the browser's rules, and neither is hidden inside the other.
Hosting splits the web build a second time. GitHub Pages cannot add CSP response headers, and the project's deployment documentation calls a meta tag the sole enforcement point there [11]. Vercel and Cloudflare Pages send real headers that mirror the meta policy [12]. Both also run a same-origin Claude proxy, at `api/claude-proxy.ts` and `functions/api/claude-proxy.ts`, built on one shared core module [12]. Users on all of these hosts see the same React interface [12].
The evidence is the project's own account, pinned to commit 2d9157c0, release v1.28.8, dated 2026-09-28 [2]. The write-up does not say when, or whether, the desktop store will get passphrase encryption. Its word is "currently" [5].
What to watch
- Whether a later WorldScript release extends passphrase-based at-rest encryption to the filesystem-backed desktop project store.
- Whether the localhost:* and 127.0.0.1:* entries in src-tauri/capabilities/default.json get narrowed to specific ports.
- Whether the project keeps GitHub Pages as a host while the meta tag remains its only CSP enforcement there.