siyuan-note/siyuan · error
resource path [%s] is not in workspace
Error message
resource path [%s] is not in workspace
What it means
Returned by ExportResources when a resource path, joined under util.WorkspaceDir, fails util.IsAbsPathInWorkspace — i.e. the resolved absolute path escapes the workspace boundary. This is a security guard against path traversal: the resource path must resolve strictly inside the workspace. Both a log line and a Go error are produced (the error echoes the offending path).
Source
Thrown at kernel/model/export.go:805
zipFilePath := filepath.Join(exportBasePath, exportID+"-"+zipFileName)
if err = os.MkdirAll(exportFolderPath, 0755); err != nil {
logging.LogErrorf("create export temp folder failed: %s", err)
return
}
defer func() {
os.RemoveAll(exportFolderPath)
if err != nil {
os.Remove(zipFilePath)
os.Remove(zipFilePath + ".partial")
}
}()
// 将需要导出的文件/文件夹复制到临时文件夹
for _, resourcePath := range resourcePaths {
resourceFullPath := filepath.Join(util.WorkspaceDir, resourcePath) // 资源完整路径
if !util.IsAbsPathInWorkspace(resourceFullPath) {
logging.LogErrorf("resource path [%s] is not in workspace", resourceFullPath)
err = errors.New("resource path [" + resourcePath + "] is not in workspace")
return
}
resourceBaseName := filepath.Base(resourceFullPath) // 资源名称
resourceCopyPath := filepath.Join(exportFolderPath, resourceBaseName) // 资源副本完整路径
if err = copyExportResource(resourceFullPath, resourceCopyPath); err != nil {
logging.LogErrorf("copy resource will be exported from [%s] to [%s] failed: %s", resourcePath, resourceCopyPath, err)
err = fmt.Errorf(Conf.Language(14), err.Error())
return
}
}
zipPartialPath := zipFilePath + ".partial"
zip, err := gulu.Zip.Create(zipPartialPath)
if err != nil {
logging.LogErrorf("create export zip [%s] failed: %s", zipFilePath, err)
return
}View on GitHub (pinned to 251596fc0d)
Solutions
- Sanitize resourcePaths before calling ExportResources — strip '..', ensure they are relative to the workspace and resolve inside it.
- If the workspace moved, re-open documents from the new workspace location so asset paths regenerate correctly.
- Reject absolute paths and traversal segments at the caller/API boundary.
- Audit plugin-supplied paths against util.IsAbsPathInWorkspace before forwarding them.
Example fix
// before — caller passes raw, possibly-traversing paths
model.ExportResources(resourcePaths, name)
// after — sanitize at the boundary
var safe []string
for _, p := range resourcePaths {
full := filepath.Join(util.WorkspaceDir, p)
if !util.IsAbsPathInWorkspace(full) {
continue // or return an error
}
safe = append(safe, p)
}
model.ExportResources(safe, name) Defensive patterns
Strategy: validation
Validate before calling
// Validate each path resolves strictly inside the workspace before exporting
for _, p := range resourcePaths {
full := filepath.Join(util.WorkspaceDir, p)
if !util.IsAbsPathInWorkspace(full) {
return fmt.Errorf("reject path outside workspace: %s", p)
}
} Type guard
// allPathsInWorkspace reports whether every path resolves inside the workspace.
func allPathsInWorkspace(paths []string) bool {
for _, p := range paths {
if !util.IsAbsPathInWorkspace(filepath.Join(util.WorkspaceDir, p)) {
return false
}
}
return true
} Prevention
- Sanitize resourcePaths at the API/plugin boundary: strip '..' and reject absolute escaping paths.
- If the workspace moved, re-open docs from the new location so asset paths regenerate.
- Never forward untrusted client-supplied paths straight to ExportResources.
When it happens
Trigger: POST /api/export/exportResources with a resourcePaths entry containing '..' segments, an absolute path outside the workspace, or a symlink-laden relative path that resolves outside. Can also occur if the workspace dir is misconfigured/moved so that previously-valid relative paths no longer resolve inside it.
Common situations: A malicious or buggy plugin/client passes crafted paths. The workspace was relocated on disk but stale relative paths remain in a document. A path with a leading slash or drive letter is treated as absolute and outside the workspace.
Related errors
- symlink [%s] resolves outside workspace: [%s]
- exporting symbolic links is not supported
- marketplace package contains an invalid path
- path escapes templates dir: %s
- path [%s] must not contain '..'
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/2bd0cdf32a3ea42c.
Report an issue: GitHub.