On 2026-09-23 an external contributor (docxology) audited the repository and filed twenty issues, then three pull requests that were merged on 2026-09-25. Until 2026-10-01 nothing in the vault mentioned them. All twenty are still open on GitHub (checked 2026-10-01). The trust model they are measured against is in Security; the refactor that addresses the structural causes is Milestone 18 - Library Refactor.

#kindin shortoverlapsfixed so faraddressed by
1securitythe server resolves a named secret and sends it as Bearer to a base_url the client chose (key exfiltration, SSRF); the claude-code binary path is client-chosen toorefactor, Milestone 18 phase 4.5: secrets go only to built-in or operator-listed endpoints (MOONKALE_LLM_ENDPOINTS); the client’s claude-code path is ignored—
2securitya “read-only” DuckDB source can still read any local file (read_csv, read_parquet, read_text, glob) and autoload extensions—fixed on dev-claude (2026-10-04): file mode read-only + enable_external_access=false; folder mode allowed_directories = the folder; no extension autoload; configuration locked—
3securitythe websocket Origin check strips the port and trusts the host name: another port on the same host, or DNS rebinding, reaches the terminal——api auth module (phase 4)
4securityextension permissions are checked with what the client sends on /api/ext/run; ids can be squatted; workspace settings grant permissions; no wasm budgetsrefactor, phase 4.5 (structural part): grants from the user scope only; an id belongs to the module file that loaded it first (no squatting). Open: fuel/epoch and memory limitsfuel/epoch limits
5securitythe folder source follows symlinks out of the root; on Windows \ and drive letters escape it——one path-jail function in project-fs
6bug, highCRLF + non-ASCII text panics the search chunker—PR #22 (the chunker); dev-claude (2026-10-04): the index locks survive a panic—
7securityrate limits keyed on a spoofable X-Forwarded-For; no limiter on /api; cookie Secure from a client header; an empty MCP token accepted——api auth module (phase 4)
8securitya cloned repository’s .moonkale/settings.json can define an agent whose command runs, and enable + grant a folder wasm extensionrefactor, phase 4.5: SettingsFile::without_authority — a folder may not set a provider, agent, shell, SSH host, grant, auto-approval or embeddings; may deny tools—
9securitythe read-only SQL gate: WITH-wrapped writes, PRAGMA, trailing statements, no Cypher gate, allow_writes auto-approves—PR #21 (CTE writes, PRAGMA names); dev-claude (2026-10-04): one statement per query, the Cypher gate on LadybugDB, allow_writes never approves destructive calls, shell commands read as words—
10securityjavascript:/data: links are clickable in the rich editor on the web; no Content-Security-Policy——link scheme allow-list; CSP header
11bug, highthe flow editor replaces an unparseable .flow.json with an empty flow and destroys it on the next edit—fixed on dev-claude (2026-10-04): a broken file shows its parse error and is never written; Reload—
12bug, highgraph renderer panics on a stale drag index (view dead until reload); the terminal pump is not restartable after a remount—fixed on dev-claude (2026-10-04): the drag follows its node by id; terminal output pumped per session (xterm replays recent output to a remounted view)—
13bugagent turns wedge: terminal.run without a timeout, unreachable approvals, a dead LSP never restartsP-069——
14robustnessunbounded buffers: PTY output to slow clients, provider streams, provider cache, fetch without a size cap———
15bug, data lossproject-fs races: create/rename TOCTOU, stale NodeIds after a directory rename, a shared temp name, trash overwrite—fixed on dev-claude (2026-10-04): create_new, no-replace rename (renameat2 on Linux/Android), ids under a renamed/deleted path forgotten, unique temp files, trash never overwritten and pruned after 30 days. Open: the low-severity notes at the end of the issue—
16bugPython and Julia symbol extraction never runs: walk::wants_text admits only markdown and Rustcontradicts spec 022 “done”fixed on refactor (Milestone 18 phase 1: one language list for the walk and the dispatch, a test that indexes .jl/.py)—
17bugentity log: slice panic on non-ASCII commit ids, O(n²) merge, dropped events, text_at after compactionP-086PR #23 (the slice); the rest openthe internal store (Internal State)
18securitySSH remote: control socket in a shared /tmp, remote port hijack, token-echo fallback, a fixed upload temp name———
19bugIME Enter sends, UTF-16 column mismatch, focus traps, image decompression bomb, full-document LSP sync, an unpinned CI downloadthe rest of P-037 (LSP didChange)——
20security, lowsecret-existence oracle, presence impersonation, transcripts in the git tree, JSON injection in websocket frames, sessions not bound to a folder———

What the issues have in common

Most of the security findings are one mistake repeated: the server trusts a decision the client made (#1 endpoint, #4 permissions, #8 settings from a folder, #20 presence names). The reason is structural — ext-api::Workspace and the settings types are shared between client and server, and the server functions accept whatever shape the client sends. The refactor’s server contribution point (phase 4 of Milestone 18 - Library Refactor) makes the server resolve providers, permissions and grants from its own state.

The second group is unbounded or unvalidated input (#2, #5, #9, #10, #14, #15). Those are local fixes and do not need to wait for the refactor.

Fixes of 2026-10-04 (dev-claude)

#2, #6, #9, #11, #12 and #15, one commit each, with tests (unit tests for the gates, the relay and the file races; browser steps for #11 and #12). Each commit says Fixes #n, so the issues close when dev-claude is merged into master. Found on the way:

  • remounting a panel (docking it elsewhere, or the phone layout) replayed the last command: a terminal panel started the last New Terminal again, the code editor ran the last Undo/Save; handlers now remember the last command they handled;
  • a hidden copy of the native terminal measured 0 × 0 and shrank the shared screen;
  • the web terminal’s websocket pumps were spawned in the component that connected it, so a remount closed the socket and the server ended the shell;
  • ext-host’s wordcount test looked for the wasm under <root>/target while building it into CARGO_TARGET_DIR.

Still open from the list: #1 and #4 (structural parts done in Milestone 18; re-check and close or narrow), #3, #5, #7, #8 (done in Milestone 18 phase 4.5 — re-check and close), #10, #13, #14, #16 (fixed; close), #17, #18, #19, #20, and the low-severity notes of #15.

Housekeeping

  • #16 is fixed (Milestone 18 phase 1) but still open; #6 closes with the dev-claude merge; #17 is partly fixed.
  • Release notes should say that these are open until they are closed: Remote and Server Modes recommends exposing a server only on a trusted network, and that stands.