You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
App: a mermaid code fence escapes its inline <script> in the mobile WebView; session file RPCs follow symlinks out of the workspace #1832
Two client/CLI defects, verified against 383c9f8b.
1. Mermaid content breaks out of its script element.MermaidRenderer.tsx:111 encodes the diagram body with JSON.stringify — a JavaScript-string encoder — and line 145 interpolates the result into an HTML script-data context. The HTML tokenizer ends the element at the first case-insensitive </script, regardless of JavaScript string state, so a fence containing </script> closes the element and the remainder is parsed as markup and executed in the WebView. The in-file comment above line 111 states that this encoding prevents exactly that.
The content is reachable from agent and tool output, from artifacts, and from workstation files rendered in the app (parseMarkdownBlock.ts:103). No CSP is set on the document.
Note the web and desktop path is not affected: mermaid 11.12.2 defaults to securityLevel: "strict", which is non-overridable, and render() runs DOMPurify. Only the native WebView branch is.
Suggested fix: escape < in the JSON output at line 111, or stop interpolating content into the document at all and pass it over postMessage after load.
2. Workspace containment is decided lexically, then operations follow paths.validatePath resolves the path as a string and compares the prefix (packages/happy-cli/src/modules/common/pathSecurity.ts:15); every handler then re-resolves that same string through link-following fs APIs (registerCommonHandlers.ts:272, :295, :359). Nothing binds the object authorized to the object operated on.
With dummy fixtures we observed: an in-workspace symlink makes readFile return an out-of-workspace file, listDirectory enumerate an out-of-workspace directory, writeFile create a file outside the workspace through a dangling link, and an ordinary read-edit-save cycle overwrite a pre-existing file outside it. The attacker here is workspace content — an untrusted clone, or the agent itself — which has no RPC access of its own, so this is not subsumed by the unrestricted machine-scoped handlers. getDirectoryTree already skips symlinks; its siblings do not.
Suggested fix: resolve the real destination before the prefix test (fs.realpath on the deepest existing ancestor, re-join the non-existent tail, compare against realpath(workingDirectory)), and prefer descriptor-based operations so the authorized object is the one used.
Activity