GHSA-9hc2-hjx8-q6pv TidGi Desktop Remote Code Execution via Malicious TiddlyWiki Repository Import — Tiddler Startup Module Auto-Execution
DescriptionTidGi Desktop through 0.13.0 contains a critical remote code execution vulnerability exploitable via a single Git repository import. The vulnerability leverages TiddlyWiki's module system, which automatically discovers and executes JavaScript code embedded in `.tid` files placed in the wiki's `tiddlers/` directory:**Auto-loading of `.tid` files** (`src/services/wiki/wikiWorker/loadWikiTiddlersWithSubWikis.ts:59-92`) — when TidGi boots a wiki workspace, `loadWikiTiddlers` reads all `.tid` files from the filesystem and adds them to the wiki store via `wiki.addTiddlers()`.**Automatic module registration** (`node_modules/tiddlywiki/boot/boot.js:2564-2565`) — `defineTiddlerModules()` iterates all tiddlers in the store. Any tiddler with a `module-type` field is passed to `$tw.modules.define()`, registering it as an executable module.**Automatic startup execution** (`node_modules/tiddlywiki/boot/boot.js:2572-2634`) — all registered modules of type `"startup"` are collected and their `exports.startup()` function is called during the boot sequence. When no `platforms` restriction is set, `doesTaskMatchPlatform()` returns `true`, and the startup function executes with full Node.js `require()` access in the Wiki Worker process.The full chain was verified on macOS with TiddlyWiki 5.4.0 and Node.js v26 — `require('child_process').execSync()` successfully executed arbitrary shell commands.Affected Product**Product**: TidGi Desktop**Vendor**: Lin Onetwo (https://github.com/tiddly-gittly)**Repository**: https://github.com/tiddly-gittly/TidGi-Desktop**Affected Versions**: 0.13.0 (latest release)**Components**: `src/services/wiki/wikiWorker/loadWikiTiddlersWithSubWikis.ts` (tiddler loading), `src/services/wiki/wikiWorker/startNodeJSWiki.ts` (wiki boot), `node_modules/tiddlywiki/boot/boot.js` (TiddlyWiki core — `defineTiddlerModules`, startup dispatch)**Package**: tidgi (npm)Vulnerability DetailsRoot Cause 1 — `.tid` Files Auto-Loaded Before Module Processing**File: `src/services/wiki/wikiWorker/loadWikiTiddlersWithSubWikis.ts:59-92`****File: `src/services/wiki/wikiWorker/startNodeJSWiki.ts:256`**This triggers `$tw.boot.startup()`, which internally calls `loadStartup()` → `loadTiddlersNode()` → `$tw.loadWikiTiddlers($tw.boot.wikiPath)` (boot.js:2381). TidGi overrides `loadWikiTiddlers` at startNodeJSWiki.ts:123 to intercept and inject sub-wiki tiddlers, but the original function still loads all `.tid` files from the main wiki's `tiddlers/` directory.Root Cause 2 — Automatic Module Registration via `module-type` Field**File: `node_modules/tiddlywiki/boot/boot.js:1514-1534`** — `defineTiddlerModules()`This function is called during `execStartup()` (boot.js:2565), **after** `loadStartup()` has already loaded all `.tid` files into the wiki store. Any tiddler with `module-type: startup` and `type: application/javascript` is automatically registered as an executable module.Root Cause 3 — Automatic Startup Execution with Full Node.js Access**File: `node_modules/tiddlywiki/boot/boot.js:2572-2576`** — Collecting startup modules**File: `node_modules/tiddlywiki/boot/boot.js:2631-2634`** — Executing startup**File: `node_modules/tiddlywiki/boot/boot.js:2658-2677`** — Platform check (passes without explicit `platforms`)Complete Boot Sequence (verified against TiddlyWiki 5.4.0)Exploitation Conditions**No authentication required** — importing a wiki is a standard feature**Only user interaction**: click "Add Workspace" → select folder/URL → confirmComplete Attack FlowProof of ConceptMinimal `.tid` File (place in `tiddlers/` directory)Verification Output (macOS, TiddlyWiki 5.4.0, Node.js v26)The message `STARTUP_EXECUTED` printed from within the attacker's `exports.startup()` function, and the file `/tmp/TidGi-RCE-PoC.txt` was created by `execSync('touch ...')`, confirming arbitrary command execution.Impact| Capability | Status | Details |
|-----------|--------|---------|
| Remote Code Execution | ✅ Full Node.js access | `require('child_process')` available |
| Arbitrary File Read | ✅ | `require('fs').readFileSync()` |
| Arbitrary File Write | ✅ | `require('fs').writeFileSync()` |
| Reverse Shell | ✅ | Node.js `net` module |
| Persistence | ✅ | Write to startup scripts, LaunchAgents, crontab |
| User Interaction | 1 click | Import repository |
| Cross-Platform | ✅ | Windows, macOS, Linux |Reproduction EvidenceStep 1 — Malicious `.tid` file contentStep 2 — TiddlyWiki boot with malicious wiki at `/tmp/evil-wiki`Step 3 — Verified RCE: `/tmp/TidGi-RCE-PoC.txt` createdPatch RecommendationFix 1: Disallow `module-type` on User TiddlersTiddlyWiki should distinguish between system tiddlers (shipped with TidGi or installed as official plugins) and user-created tiddlers. User-created tiddlers should never be allowed to define `module-type`.Fix 2: Sandbox User ModulesIf user-created modules must be supported, execute them in a restricted context without access to Node.js built-ins:Fix 3: Whitelist Allowed `module-type` ValuesOnly allow known safe `module-type` values for user tiddlers:
CVSS v3.1 score: 9.6