SiYuan, Stored XSS to RCE, CVE-2026-44588 (Neighbor) -DC-Jul2026-869

Listen to this Post

The Electron desktop client of SiYuan (versions ≤ 3.6.5) is configured with `nodeIntegration: true` and `contextIsolation: false` (app/electron/main.js:307), which permits any JavaScript executing in the renderer to directly invoke Node.js APIs, including require('child_process'). This design flaw turns any cross-site scripting (XSS) vulnerability into a full remote code execution (RCE) primitive.
This vulnerability is a neighbor-bug of CVE-2026-44588. The earlier fix for -44588 introduced `escapeAriaLabel()` (which double-escapes `<` to survive the attribute → `getAttribute` → `innerHTML` round-trip), but the Attribute View (AV) asset cell renderers were overlooked and remain using the weaker `escapeAttr()` (escapes only `"` and ) or no escaping at all.
Two distinct XSS sinks exist. Sink 1 is a direct stored XSS that triggers immediately on page load. In app/src/protyle/render/av/cell.ts:1008, the code concatenates:
text +=${item.name || item.content};
The `>${item.name || item.content}
` portion is raw user input with zero escaping. Even worse, in app/src/protyle/render/av/blockAttr.ts:93, the code is completely unescaped:

`html += ``;`

These are rendered via `action.ts:860` (cellElement.innerHTML = renderCell(...)), resulting in immediate XSS on page load.
Sink 2 is a hover-triggered XSS via an aria-label round-trip. The same lines emit `aria-label=”${escapeAttr(item.content)}”` on `.ariaLabel` elements. `escapeAttr()` (util/escape.ts:14) only escapes `”` and `’` — not `<` or >. A global mouseover handler in `popover.ts:33` reads `aria-label` via `getAttribute` (which attribute-decodes entities), then at line 144 calls showTooltip(decodeURIComponent(tip), ...). In tooltip.ts:41, `messageElement.innerHTML = message` executes the payload on hover.
The source of the malicious input is app/src/protyle/render/av/asset.ts:405, where `addAssetLink()` reads user input from a free-form `