siyuan-note/siyuan · error
path escapes workspace: %s
Error message
path escapes workspace: %s
What it means
Thrown by the `absPath` helper shared across all `file` subcommands when a workspace-relative path, after cleaning and joining against `util.WorkspaceDir`, resolves outside the workspace root. The guard uses `gulu.File.IsSubPath` to ensure the CLI cannot read or write files beyond the workspace boundary, preventing path traversal.
Source
Thrown at kernel/cli/cmd/file.go:44
"text/tabwriter"
"github.com/88250/gulu"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/spf13/cobra"
)
var fileCmd = &cobra.Command{
Use: "file",
Short: "Workspace file operations",
}
func absPath(rel string) (string, error) {
rel = filepath.Clean(strings.ReplaceAll(rel, "/", string(os.PathSeparator)))
abs := filepath.Join(util.WorkspaceDir, rel)
if !gulu.File.IsSubPath(util.WorkspaceDir, abs) {
return "", fmt.Errorf("path escapes workspace: %s", rel)
}
if boxID := model.EncryptedRawPathBoxID(abs); boxID != "" {
return "", fmt.Errorf("path belongs to encrypted notebook [%s]: %s", boxID, rel)
}
return abs, nil
}
var fileListCmd = &cobra.Command{
Use: "list <path>",
Short: "List directory contents",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
dir, err := absPath(args[0])
if err != nil {
return err
}
entries, err := os.ReadDir(dir)
if err != nil {View on GitHub (pinned to 251596fc0d)
Solutions
- Use a path relative to the workspace root without `..` traversal, e.g. `data/20240101120000-abc/document.sy`
- If you need host-absolute access, the CLI intentionally forbids it — use the kernel HTTP API with appropriate scope instead
- Check for symlinks in the supplied path and replace them with real workspace paths
Example fix
// before siyuan file list ../../../conf // after siyuan file list data/20240101120000-abc
Defensive patterns
Strategy: validation
Validate before calling
rel := strings.TrimSpace(userPath)
if strings.HasPrefix(rel, "/") || strings.HasPrefix(rel, "..") || strings.Contains(rel, "..") {
return fmt.Errorf("refusing workspace-relative path that may escape: %s", rel)
} Prevention
- Always pass paths relative to the workspace root, never host-absolute paths
- Reject any path containing `..` before calling the CLI
- Audit symlinks inside the workspace that point outward
When it happens
Trigger: Passing a path containing `..` segments that climb above the workspace (e.g. `../../etc/passwd`), an absolute path that resolves elsewhere, or a symlink-laden relative path that escapes after join. Any `file` subcommand (`list`, `read`, `write`, `grep`, `copy`) routes its argument through `absPath` and surfaces this error.
Common situations: Scripts that build paths from untrusted or relative components; users assuming the path is absolute on the host filesystem rather than workspace-relative; symlinks inside the workspace pointing outward.
Related errors
- path belongs to encrypted notebook [%s]: %s
- --pattern is required
- --path is required
- --path is required
- --file is required
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/3c24a07237f8e4d9.
Report an issue: GitHub.