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

  1. Use a path relative to the workspace root without `..` traversal, e.g. `data/20240101120000-abc/document.sy`
  2. If you need host-absolute access, the CLI intentionally forbids it — use the kernel HTTP API with appropriate scope instead
  3. 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

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


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/3c24a07237f8e4d9. Report an issue: GitHub.