SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem
### Summary `/api/file/getUniqueFilename` takes a path from the request body and passes it to a filesystem existence check with no validation, confinement or authorization. The response distinguishes paths that exist from paths that do not, so an anonymous reader in publish mode can probe arbitrary locations on the host, one request per probe. Files and directories both work. Every neighbouring file route either requires an administrator or confines the path first. ### Details **Route.** `kernel/api/router.go:289` on master, `:292` on the development branch, `CheckAuth` only. **Handler,** `kernel/api/file.go:84`, in full: ```go util.ParseJsonArgs(arg, ret, util.BindJsonArg("path", &filePath, true, true)) ret.Data = map[string]any{"path": util.GetUniqueFilename(filePath)} ``` **The argument binder does no path handling.** `util.BindJsonArg` (`kernel/util/net.go:365`) takes two booleans, `required` (the key must be present) and `rejectEmpty` (the value must be non-empty). That is its entire contract. There is no `filepath.Clean`, no workspace join, no traversal check. An absolute path outside the workspace reaches `gulu.File.IsExist` unmodified. **The oracle.** `util/file.go:67`: ```go if !gulu.File.IsExist(filePath) { return filePath } // otherwise loop, returning the first non-existent dir/base (i).ext ``` Input echoed back means the path does not exist. A `(1)` suffix means it does. **The asymmetry.** | Route | Middleware | |---|---| | `putFile`, `copyFile`, `globalCopyFiles
- Products
- github.com/siyuan-note/siyuan/kernel
- Affected versions
- Not specified
- Fixed versions
- 0.0.0-20260812083335-251596fc0de2
- CVEs
- CVE-2026-73605
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 28 Oct 2026, 08:46 UTC · Revision 1
Source evidence
SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem
core-osv · Original sourcePublished 1 Oct 2026, 15:46 UTC
### Summary `/api/file/getUniqueFilename` takes a path from the request body and passes it to a filesystem existence check with no validation, confinement or authorization. The response distinguishes paths that exist from paths that do not, so an anonymous reader in publish mode can probe arbitrary locations on the host, one request per probe. Files and directories both work. Every neighbouring file route either requires an administrator or confines the path first. ### Details **Route.** `kernel/api/router.go:289` on master, `:292` on the development branch, `CheckAuth` only. **Handler,** `kernel/api/file.go:84`, in full: ```go util.ParseJsonArgs(arg, ret, util.BindJsonArg("path", &filePath, true, true)) ret.Data = map[string]any{"path": util.GetUniqueFilename(filePath)} ``` **The argument binder does no path handling.** `util.BindJsonArg` (`kernel/util/net.go:365`) takes two booleans, `required` (the key must be present) and `rejectEmpty` (the value must be non-empty). That is its entire contract. There is no `filepath.Clean`, no workspace join, no traversal check. An absolute path outside the workspace reaches `gulu.File.IsExist` unmodified. **The oracle.** `util/file.go:67`: ```go if !gulu.File.IsExist(filePath) { return filePath } // otherwise loop, returning the first non-existent dir/base (i).ext ``` Input echoed back means the path does not exist. A `(1)` suffix means it does. **The asymmetry.** | Route | Middleware | |---|---| | `putFile`, `copyFile`, `globalCopyFiles
osv:GHSA-hf8h-97gm-4x2p
github.com/siyuan-note/siyuan/kernel
Fixed versions: 0.0.0-20260812083335-251596fc0de2
Complete source record
{
"id": "d64f1c5e09dd7493994943bd114abc7b5cc5c9a1e3ef4ebc0eb6a4ae77b268b6",
"url": "https://osv.dev/vulnerability/GHSA-hf8h-97gm-4x2p",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem",
"summary": "### Summary `/api/file/getUniqueFilename` takes a path from the request body and passes it to a filesystem existence check with no validation, confinement or authorization. The response distinguishes paths that exist from paths that do not, so an anonymous reader in publish mode can probe arbitrary locations on the host, one request per probe. Files and directories both work. Every neighbouring file route either requires an administrator or confines the path first. ### Details **Route.** `kernel/api/router.go:289` on master, `:292` on the development branch, `CheckAuth` only. **Handler,** `kernel/api/file.go:84`, in full: ```go util.ParseJsonArgs(arg, ret, util.BindJsonArg(\"path\", &filePath, true, true)) ret.Data = map[string]any{\"path\": util.GetUniqueFilename(filePath)} ``` **The argument binder does no path handling.** `util.BindJsonArg` (`kernel/util/net.go:365`) takes two booleans, `required` (the key must be present) and `rejectEmpty` (the value must be non-empty). That is its entire contract. There is no `filepath.Clean`, no workspace join, no traversal check. An absolute path outside the workspace reaches `gulu.File.IsExist` unmodified. **The oracle.** `util/file.go:67`: ```go if !gulu.File.IsExist(filePath) { return filePath } // otherwise loop, returning the first non-existent dir/base (i).ext ``` Input echoed back means the path does not exist. A `(1)` suffix means it does. **The asymmetry.** | Route | Middleware | |---|---| | `putFile`, `copyFile`, `globalCopyFiles",
"evidence": "osv:GHSA-hf8h-97gm-4x2p",
"products": [
{
"name": {
"value": "github.com/siyuan-note/siyuan/kernel",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "0.0.0-20260812083335-251596fc0de2",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": []
}
],
"severity": "medium",
"structured": {
"id": "GHSA-hf8h-97gm-4x2p",
"aliases": [
"CVE-2026-73605",
"GHSA-hf8h-97gm-4x2p",
"GO-2026-6626"
],
"metrics": [
{
"type": "CVSS_V3",
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N"
}
],
"affected": [
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20260812083335-251596fc0de2"
}
]
}
],
"package": {
"name": "github.com/siyuan-note/siyuan/kernel",
"purl": "pkg:golang/github.com/siyuan-note/siyuan/kernel",
"ecosystem": "Go"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-hf8h-97gm-4x2p/GHSA-hf8h-97gm-4x2p.json"
}
}
],
"modified": "2026-10-07T17:55:29.509304430Z",
"provider": "osv",
"references": [
"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-hf8h-97gm-4x2p",
"https://nvd.nist.gov/vuln/detail/CVE-2026-73605",
"https://github.com/siyuan-note/siyuan",
"https://www.vulncheck.com/advisories/siyuan-before-path-traversal-via-getuniquefilename"
],
"provider_metadata": {
"cwe_ids": [
"CWE-862"
],
"severity": "MODERATE",
"github_reviewed": true,
"nvd_published_at": null,
"github_reviewed_at": "2026-10-01T15:46:01Z"
}
},
"related_cves": [
{
"value": "CVE-2026-73605",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 97116,
"published_at": "2026-10-01T15:46:01+00:00"
}SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem in github.com/siyuan-note/siyuan/ke
core-osv · Original sourcePublished 7 Oct 2026, 14:09 UTC
SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem in github.com/siyuan-note/siyuan/kernel
osv:GO-2026-6626
github.com/siyuan-note/siyuan/kernel
Fixed versions: 0.0.0-20260812083335-251596fc0de2
Complete source record
{
"id": "b1bea559e274368a3f5921e091cc0c64cbf9f6f88e99f801b995e8ab59e0f23e",
"url": "https://osv.dev/vulnerability/GO-2026-6626",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem in github.com/siyuan-note/siyuan/ke",
"summary": "SiYuan: getUniqueFilename passes an unvalidated client-supplied path to the filesystem, giving anonymous readers an existence oracle over the entire host filesystem in github.com/siyuan-note/siyuan/kernel",
"evidence": "osv:GO-2026-6626",
"products": [
{
"name": {
"value": "github.com/siyuan-note/siyuan/kernel",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "0.0.0-20260812083335-251596fc0de2",
"evidence": "/affected/0/ranges"
}
],
"affected_versions": []
}
],
"severity": "unknown",
"structured": {
"id": "GO-2026-6626",
"aliases": [
"CVE-2026-73605",
"GHSA-hf8h-97gm-4x2p",
"GO-2026-6626"
],
"affected": [
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "0.0.0-20260812083335-251596fc0de2"
}
]
}
],
"package": {
"name": "github.com/siyuan-note/siyuan/kernel",
"purl": "pkg:golang/github.com/siyuan-note/siyuan/kernel",
"ecosystem": "Go"
},
"database_specific": {
"source": "https://vuln.go.dev/ID/GO-2026-6626.json"
},
"ecosystem_specific": {}
}
],
"modified": "2026-10-07T17:45:13.480332339Z",
"provider": "osv",
"references": [
"https://github.com/siyuan-note/siyuan/security/advisories/GHSA-hf8h-97gm-4x2p",
"https://nvd.nist.gov/vuln/detail/CVE-2026-73605",
"https://www.vulncheck.com/advisories/siyuan-before-path-traversal-via-getuniquefilename"
],
"provider_metadata": {
"url": "https://pkg.go.dev/vuln/GO-2026-6626",
"review_status": "UNREVIEWED"
}
},
"related_cves": [
{
"value": "CVE-2026-73605",
"evidence": "/aliases"
}
],
"security_relevant": true,
"severity_evidence": null
},
"source_id": "core-osv",
"document_id": 97106,
"published_at": "2026-10-07T14:09:59+00:00"
}