{"id":"CVE-2026-50551","aliases":["GHSA-56mp-4f3v-fgj2"],"title":"SiYuan: Stored XSS to RCE via Unsanitized Attribute View Asset Cell Content","summary":"SiYuan: Stored XSS to RCE via Unsanitized Attribute View Asset Cell Content","severity":"critical","cvss":9.9,"cwe":["CWE-79"],"vendor":"siyuan-note","product":"github.com/siyuan-note/siyuan/kernel","ecosystem":"go","affected":["github.com/siyuan-note/siyuan/kernel < 0.0.0-20260628153353-2d5d72223df4"],"patched":["github.com/siyuan-note/siyuan/kernel 0.0.0-20260628153353-2d5d72223df4"],"published":"2026-07-10","updated":"2026-07-10","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-56mp-4f3v-fgj2","references":[{"url":"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-56mp-4f3v-fgj2"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-50551"},{"url":"https://github.com/advisories/GHSA-56mp-4f3v-fgj2"}],"tags":["ghsa","go"],"epss":0.0044,"epssPercentile":0.35475,"ingestedAt":"2026-07-10T21:06:31.405Z","slug":"CVE-2026-50551","body":"## Overview\n\nSiYuan v3.6.5 and earlier versions contain a stored cross-site scripting (XSS) vulnerability in the Attribute View (database) asset cell renderer that escalates to remote code execution (RCE) in the Electron desktop client. This is a neighbor-bug of CVE-2026-44588: the fix for -44588 used `escapeAriaLabel()` (double-escapes `<`), but the AV asset renderers were left using the weaker `escapeAttr()` (escapes only quotes) or no escaping at all.\n\n  ## Vulnerability Details\n\n  The Electron renderer is configured with `nodeIntegration: true` and `contextIsolation: false` (app/electron/main.js:307), allowing any JavaScript executing in the renderer to directly access Node.js APIs including `require('child_process')`.\n\n  Two XSS sinks exist.\n\n  ### Sink 1 (Direct Stored XSS - triggers on page load)\n\n  `app/src/protyle/render/av/cell.ts:1008`:\n\n      text += `<span class=\"b3-chip av__celltext--url ariaLabel\" aria-label=\"${escapeAttr(item.content)}\" data-name=\"${escapeAttr(item.name)}\"\n  data-url=\"${escapeAttr(item.content)}\">${item.name || item.content}</span>`;\n\n  The `>${item.name || item.content}</span>` portion is raw user input with zero escaping.\n\n  `app/src/protyle/render/av/blockAttr.ts:93` (even worse - completely unescaped):\n\n      html += `<img loading=\"lazy\" class=\"av__cellassetimg ariaLabel\" aria-label=\"${item.content}\" src=\"${getCompressURL(item.content)}\">`;\n\n  Rendered via `action.ts:860`: `cellElement.innerHTML = renderCell(...)` results in immediate XSS on page load.\n\n  ### Sink 2 (Hover-triggered XSS via aria-label round-trip)\n\n  - Same lines emit `aria-label=\"${escapeAttr(item.content)}\"` on `.ariaLabel` elements.\n  - `escapeAttr()` (util/escape.ts:14) escapes only `\"` and `'` — NOT `<` or `>`.\n  - `popover.ts:33` global mouseover handler reads `aria-label` via `getAttribute` (which attribute-decodes entities).\n  - Line 144: `showTooltip(decodeURIComponent(tip), ...)` then `tooltip.ts:41`: `messageElement.innerHTML = message` results in XSS on hover.\n\n  ### Source\n\n  - `app/src/protyle/render/av/asset.ts:405`: `addAssetLink()` reads user input from a free-form `<textarea>` with no sanitization.\n  - Kernel stores `MAsset.Content` raw (kernel/av/value.go:53), no server-side sanitization.\n\n  ## Attack Vector\n\n  1. Attacker creates a malicious note containing an Attribute View (database).\n  2. Attacker adds an asset cell with link content: `<img src=x onerror=require('child_process').exec('calc')>`\n  3. Victim opens the note for immediate RCE (Sink 1), or hovers over the cell for RCE (Sink 2).\n  4. In a sync/collaboration scenario, the malicious note propagates to all users.\n\n  ## Proof of Concept\n\n  Payload (Direct XSS) — in an AV asset cell link field, enter:\n\n      <img src=x onerror=alert(document.domain)>\n\n  For RCE in Electron desktop:\n\n      <img src=x onerror=require('child_process').exec('calc')>\n\n  ### Steps to Reproduce\n\n  1. Open SiYuan desktop app (v3.6.5).\n  2. Create a new document.\n  3. Insert an Attribute View (database): `/` then select \"Table\".\n  4. Add a column of type \"Asset\".\n  5. Click the asset cell, then \"Add Link\".\n  6. In the \"Link\" textarea, paste: `<img src=x onerror=alert(1)>`\n  7. Leave \"Title\" empty or fill with benign text.\n  8. Click outside the dialog to save.\n  9. Observe: Alert fires immediately (Sink 1). Hovering over the cell also triggers (Sink 2).\n\n  ## Impact\n\n  - Remote Code Execution on victim's system via malicious note sync/import.\n  - Data exfiltration: attacker can read all notes, access filesystem, steal credentials.\n  - Persistence: malicious payload stored in `.sy` files, executes on every open.\n\n  ## Suggested Fix\n\n  1. Replace `escapeAttr()` with `escapeAriaLabel()` for all `aria-label` attributes in AV cell renderers.\n  2. Escape `item.name` and `item.content` with `escapeHtml()` before concatenating into element text content.\n\n  Affected files: `app/src/protyle/render/av/cell.ts`, `app/src/protyle/render/av/blockAttr.ts`, `app/src/protyle/render/av/asset.ts`.\n\n  ## Additional Context\n\n  This vulnerability is a neighbor-bug of CVE-2026-44588. The fix for -44588 correctly used `escapeAriaLabel()` (which double-escapes `<` to survive the attribute -> `getAttribute` -> `innerHTML` round-trip), but the AV asset cell renderers were left using the weaker `escapeAttr()` or no escaping. This is part of a pattern of incomplete fixes in SiYuan (see also CVE-2026-33066, CVE-2026-29183). The long-term fix should set Electron`contextIsolation: true` and `nodeIntegration: false`.\n\n  ## Report\n Reporter (GitHub: Yunkaiwjs).\n\n## Affected packages\n\n- `github.com/siyuan-note/siyuan/kernel < 0.0.0-20260628153353-2d5d72223df4`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/siyuan-note/siyuan/kernel 0.0.0-20260628153353-2d5d72223df4`","depth":"midnight","depthScore":55,"depthScoreParts":{"impact":54.5,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}