VYPR
High severity7.5OSV Advisory· Published Jan 19, 2026· Updated Apr 29, 2026

CVE-2026-23850

CVE-2026-23850

Description

SiYuan is a personal knowledge management system. In versions prior to 3.5.4, the markdown feature allows unrestricted server side html-rendering which allows arbitrary file read (LFD). Version 3.5.4 fixes the issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/siyuan-note/siyuan/kernelGo
< 0.0.0-20260118092326-b2274baba2e10.0.0-20260118092326-b2274baba2e1

Affected products

1

Patches

2
f8f4b517077b

:lock: Arbitrary file reading vulnerability https://github.com/siyuan-note/siyuan/issues/16860

https://github.com/siyuan-note/siyuanDanielJan 18, 2026via ghsa
1 file changed · +1 0
  • kernel/util/path.go+1 0 modified
    @@ -416,6 +416,7 @@ func IsSensitivePath(p string) bool {
     		"passwd":          {},
     		"shadow":          {},
     		"pgpass":          {},
    +		"hosts":           {},
     		"credentials":     {}, // 如 aws credentials
     		"config.json":     {}, // docker config.json 可能含 token
     	}
    
b2274baba2e1

:lock: Arbitrary file reading vulnerability https://github.com/siyuan-note/siyuan/issues/16860

https://github.com/siyuan-note/siyuanDanielJan 18, 2026via ghsa
3 files changed · +118 3
  • kernel/api/file.go+14 2 modified
    @@ -66,14 +66,26 @@ func globalCopyFiles(c *gin.Context) {
     		srcs = append(srcs, s.(string))
     	}
     
    -	for _, src := range srcs {
    -		if !filelock.IsExist(src) {
    +	for i, src := range srcs {
    +		absSrc, _ := filepath.Abs(src)
    +
    +		if !filelock.IsExist(absSrc) {
     			msg := fmt.Sprintf("file [%s] does not exist", src)
     			logging.LogErrorf(msg)
     			ret.Code = -1
     			ret.Msg = msg
     			return
     		}
    +
    +		if util.IsSensitivePath(absSrc) {
    +			msg := fmt.Sprintf("refuse to copy sensitive file [%s]", src)
    +			logging.LogErrorf(msg)
    +			ret.Code = -2
    +			ret.Msg = msg
    +			return
    +		}
    +
    +		srcs[i] = absSrc
     	}
     
     	destDir := arg["destDir"].(string) // 相对于工作空间的路径
    
  • kernel/model/assets.go+12 1 modified
    @@ -248,7 +248,18 @@ func netAssets2LocalAssets0(tree *parse.Tree, onlyImg bool, originalURL string,
     					u = u[:strings.Index(u, "?")]
     				}
     
    -				if !gulu.File.IsExist(u) || gulu.File.IsDir(u) {
    +				if !gulu.File.IsExist(u) {
    +					logging.LogErrorf("local file asset [%s] not exist", u)
    +					continue
    +				}
    +
    +				if gulu.File.IsDir(u) {
    +					logging.LogWarnf("ignore converting directory path [%s] to local asset", u)
    +					continue
    +				}
    +
    +				if util.IsSensitivePath(u) {
    +					logging.LogWarnf("ignore converting sensitive path [%s] to local asset", u)
     					continue
     				}
     
    
  • kernel/util/path.go+92 0 modified
    @@ -347,3 +347,95 @@ func IsPartitionRootPath(path string) bool {
     		return cleanPath == "/"
     	}
     }
    +
    +// IsSensitivePath 对传入路径做统一的敏感性检测。
    +func IsSensitivePath(p string) bool {
    +	if p == "" {
    +		return false
    +	}
    +	pp := filepath.Clean(strings.ToLower(p))
    +
    +	// 精确敏感文件
    +	exact := []string{
    +		"/etc/passwd",
    +		"/etc/shadow",
    +		"/etc/gshadow",
    +		"/var/run/secrets/kubernetes.io/serviceaccount/token",
    +	}
    +	for _, e := range exact {
    +		if pp == e {
    +			return true
    +		}
    +	}
    +
    +	// 敏感目录前缀(UNIX 风格)
    +	prefixes := []string{
    +		"/etc/ssh",
    +		"/root",
    +		"/etc/ssl",
    +		"/etc/letsencrypt",
    +		"/var/lib/docker",
    +		"/.gnupg",
    +		"/.ssh",
    +		"/.aws",
    +		"/.kube",
    +		"/.docker",
    +		"/.config/gcloud",
    +	}
    +	for _, pre := range prefixes {
    +		if strings.HasPrefix(pp, pre) {
    +			return true
    +		}
    +	}
    +
    +	// Windows 常见敏感目录(小写比较)
    +	winPrefixes := []string{
    +		`c:\windows\system32`,
    +		`c:\windows\system`,
    +		`c:\users\`,
    +	}
    +	for _, wp := range winPrefixes {
    +		if strings.HasPrefix(pp, strings.ToLower(wp)) {
    +			return true
    +		}
    +	}
    +
    +	// 文件名级别检查
    +	base := filepath.Base(pp)
    +	n := strings.ToLower(base)
    +	sensitiveNames := map[string]struct{}{
    +		".env":            {},
    +		".env.local":      {},
    +		".npmrc":          {},
    +		".netrc":          {},
    +		"id_rsa":          {},
    +		"id_dsa":          {},
    +		"id_ecdsa":        {},
    +		"id_ed25519":      {},
    +		"authorized_keys": {},
    +		"passwd":          {},
    +		"shadow":          {},
    +		"pgpass":          {},
    +		"credentials":     {}, // 如 aws credentials
    +		"config.json":     {}, // docker config.json 可能含 token
    +	}
    +	if _, ok := sensitiveNames[n]; ok {
    +		return true
    +	}
    +	// 支持 .env.* 之类的模式
    +	if n == ".env" || strings.HasPrefix(n, ".env.") {
    +		return true
    +	}
    +
    +	// 扩展名级别检查
    +	ext := strings.ToLower(filepath.Ext(n))
    +	sensitiveExts := []string{
    +		".pem", ".key", ".p12", ".pfx", ".ppk", ".asc", ".gpg",
    +	}
    +	for _, se := range sensitiveExts {
    +		if ext == se {
    +			return true
    +		}
    +	}
    +	return false
    +}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.