siyuan-note/siyuan · error
path escapes templates dir
Error message
path escapes templates dir: %s
What it means
resolveTemplateAbs normalizes the requested path and verifies via filepath.Rel that it stays inside data/templates. If the cleaned path resolves outside the templates base directory (relative component starting with ".."), the error is returned to block path traversal. It protects templates access from reading arbitrary filesystem locations.
Solutions
- Move the template file into data/templates and reference it relatively.
- Use an absolute path that actually lives under data/templates.
- Remove ".." segments from the path; anchor it at data/templates.
Example fix
// before template get --path ../notes/tpl.sy // after template get --path data/templates/tpl.sy (or copy tpl.sy into data/templates and use --path tpl.sy)
Defensive patterns
Strategy: validation
Validate before calling
const templatesBase = "/path/to/data/templates";
const abs = require("path").resolve(templatesBase, userPath);
if (!abs.startsWith(templatesBase + require("path").sep)) throw new Error("path escapes templates dir"); Prevention
- Place templates under data/templates and reference them relatively.
- Never accept ".." segments from user input for template paths.
- Resolve and verify containment before calling the CLI.
When it happens
Trigger: Passing --path with traversal segments such as "../foo" or "/abs/path/outside/templates" that Clean/Rel shows escapes data/templates.
Common situations: Typing a path relative to the working directory instead of data/templates; using ".." to reach another data subfolder; scripts building paths by joining user input without sanitization.
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
- content template path is outside templates directory
- path escapes workspace
- archive entry resolves outside destination
- asset escapes its directory
- asset path escapes data directory
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/0542bc3f6e18297f.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/cli/cmd/template.go:214
return nil
},
}
// resolveTemplateAbs 把模板路径解析为 data/templates 下的绝对路径,拒绝越界。
// 接受绝对路径或相对 data/templates 的相对路径。
func resolveTemplateAbs(p string) (string, error) {
if p == "" {
return "", fmt.Errorf("--path is required")
}
abs := p
if !filepath.IsAbs(abs) {
abs = filepath.Join(util.DataDir, "templates", p)
}
abs = filepath.Clean(abs)
templatesBase := filepath.Clean(filepath.Join(util.DataDir, "templates"))
rel, err := filepath.Rel(templatesBase, abs)
if err != nil || strings.HasPrefix(rel, "..") || rel == ".." {
return "", fmt.Errorf("path escapes templates dir: %s", p)
}
return abs, nil
}
func init() {
templateGetCmd.Flags().String("path", "", "template path (absolute or relative to data/templates)")
templateRemoveCmd.Flags().String("path", "", "template path (absolute or relative to data/templates)")
templateRenderCmd.Flags().String("path", "", "template path (absolute or relative to data/templates)")
templateRenderCmd.Flags().String("id", "", "block ID to render against")
templateSaveAsCmd.Flags().String("id", "", "source document block ID")
templateSaveAsCmd.Flags().String("name", "", "template name without extension")
templateSaveAsCmd.Flags().Bool("overwrite", false, "overwrite if exists")
templateCreateCmd.Flags().String("name", "", "template name without extension")
templateCreateCmd.Flags().String("data", "", "markdown content")
templateCreateCmd.Flags().String("file", "", "read content from file path (- for stdin)")
templateCreateCmd.Flags().Bool("overwrite", false, "overwrite if exists")
rootCmd.AddCommand(templateCmd)View on GitHub (pinned to 9f775e8a12)