{"record":{"id":"3c24a07237f8e4d9","repo":"siyuan-note/siyuan","slug":"path-escapes-workspace-s","errorCode":null,"errorMessage":"path escapes workspace: %s","messagePattern":"path escapes workspace: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/file.go","lineNumber":44,"sourceCode":"\t\"text/tabwriter\"\n\n\t\"github.com/88250/gulu\"\n\t\"github.com/siyuan-note/siyuan/kernel/model\"\n\t\"github.com/siyuan-note/siyuan/kernel/util\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar fileCmd = &cobra.Command{\n\tUse:   \"file\",\n\tShort: \"Workspace file operations\",\n}\n\nfunc absPath(rel string) (string, error) {\n\trel = filepath.Clean(strings.ReplaceAll(rel, \"/\", string(os.PathSeparator)))\n\tabs := filepath.Join(util.WorkspaceDir, rel)\n\tif !gulu.File.IsSubPath(util.WorkspaceDir, abs) {\n\t\treturn \"\", fmt.Errorf(\"path escapes workspace: %s\", rel)\n\t}\n\tif boxID := model.EncryptedRawPathBoxID(abs); boxID != \"\" {\n\t\treturn \"\", fmt.Errorf(\"path belongs to encrypted notebook [%s]: %s\", boxID, rel)\n\t}\n\treturn abs, nil\n}\n\nvar fileListCmd = &cobra.Command{\n\tUse:   \"list <path>\",\n\tShort: \"List directory contents\",\n\tArgs:  cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tdir, err := absPath(args[0])\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tentries, err := os.ReadDir(dir)\n\t\tif err != nil {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/cli/cmd/file.go#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nsiyuan file list ../../../conf\n// after\nsiyuan file list data/20240101120000-abc","handlingStrategy":"validation","validationCode":"rel := strings.TrimSpace(userPath)\nif strings.HasPrefix(rel, \"/\") || strings.HasPrefix(rel, \"..\") || strings.Contains(rel, \"..\") {\n    return fmt.Errorf(\"refusing workspace-relative path that may escape: %s\", rel)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["cli","path-security","validation","traversal","go","siyuan"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}