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

  1. Move the template file into data/templates and reference it relatively.
  2. Use an absolute path that actually lives under data/templates.
  3. 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

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


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)