siyuan-note/siyuan · error
asset path is outside data directory
Error message
asset path is outside data directory
What it means
dataRelativeAssetPath computes the path relative to util.DataDir and rejects any path that escapes the data directory (result ".." or starting with "../", or a failed Rel computation). SiYuan throws this as a path-traversal guard so asset download cannot target files outside the workspace data directory.
Source
Thrown at kernel/model/asset_download.go:121
case conf.ProviderSiYuan:
if !IsSubscriber() {
return errors.New(Conf.Language(376))
}
case conf.ProviderS3, conf.ProviderWebDAV, conf.ProviderLocal:
if !IsPaidUser() {
return errors.New(Conf.Language(376))
}
}
return nil
}
func dataRelativeAssetPath(absPath string) (string, error) {
if !filepath.IsAbs(absPath) {
return "", fmt.Errorf("asset path must be absolute")
}
rel, err := filepath.Rel(util.DataDir, filepath.Clean(absPath))
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return "", fmt.Errorf("asset path is outside data directory")
}
if rel == "." {
return "/", nil
}
return "/" + filepath.ToSlash(rel), nil
}
// EnsureAssetLocal 在调用方完成访问校验后补齐资源,下载内容仍由原有读取流程认证。
func EnsureAssetLocal(absPath string) error {
if _, err := os.Stat(absPath); err == nil {
return nil
} else if !errors.Is(err, os.ErrNotExist) {
return err
}
assetDownloadSourceMu.RLock()
defer assetDownloadSourceMu.RUnlock()
rel, err := dataRelativeAssetPath(absPath)
if err != nil {View on GitHub (pinned to 8641553a1f)
Solutions
- Verify the path is inside util.DataDir before calling (filepath.Rel and prefix check)
- Clean the path and remove .. components; reject escape attempts
- If the asset legitimately lives elsewhere, copy it into the workspace assets folder first
Example fix
// before
model.EnsureAssetLocal("/etc/hosts") // outside data dir
// after
rel, _ := filepath.Rel(util.DataDir, target)
if rel == ".." || strings.HasPrefix(rel, "..") {
return fmt.Errorf("asset outside data dir")
}
model.EnsureAssetLocal(target) Defensive patterns
Strategy: validation
Validate before calling
rel, err := filepath.Rel(util.DataDir, filepath.Clean(p))
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
return fmt.Errorf("path escapes data dir")
} Prevention
- Sanitize and Clean user/plugin-supplied paths before use
- Reject .. segments and symlinks that resolve outside util.DataDir
- Keep assets inside the workspace assets directory
When it happens
Trigger: Calling EnsureAssetLocal or EnsureAssetPrefixLocal with an absolute path that resolves outside util.DataDir, e.g. /etc/passwd or a sibling directory path via .. segments.
Common situations: Passing user-supplied paths without sanitization; symlinks resolving outside the data dir; constructing paths from untrusted plugin input; migrating code that used paths from a different workspace.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- invalid custom emoji name
- path [%s] must not contain '..'
- path [%s] escapes box directory
- asset path escapes data directory: %s
- invalid package name
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/e7fd662be5b87499.
Report an issue: GitHub.