{"record":{"id":"0542bc3f6e18297f","repo":"siyuan-note/siyuan","slug":"path-escapes-templates-dir-s","errorCode":null,"errorMessage":"path escapes templates dir: %s","messagePattern":"path escapes templates dir: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/template.go","lineNumber":202,"sourceCode":"\t\treturn nil\n\t},\n}\n\n// resolveTemplateAbs 把模板路径解析为 data/templates 下的绝对路径，拒绝越界。\n// 接受绝对路径或相对 data/templates 的相对路径。\nfunc resolveTemplateAbs(p string) (string, error) {\n\tif p == \"\" {\n\t\treturn \"\", fmt.Errorf(\"--path is required\")\n\t}\n\tabs := p\n\tif !filepath.IsAbs(abs) {\n\t\tabs = filepath.Join(util.DataDir, \"templates\", p)\n\t}\n\tabs = filepath.Clean(abs)\n\ttemplatesBase := filepath.Clean(filepath.Join(util.DataDir, \"templates\"))\n\trel, err := filepath.Rel(templatesBase, abs)\n\tif err != nil || strings.HasPrefix(rel, \"..\") || rel == \"..\" {\n\t\treturn \"\", fmt.Errorf(\"path escapes templates dir: %s\", p)\n\t}\n\treturn abs, nil\n}\n\nfunc init() {\n\ttemplateGetCmd.Flags().String(\"path\", \"\", \"template path (absolute or relative to data/templates)\")\n\ttemplateRemoveCmd.Flags().String(\"path\", \"\", \"template path (absolute or relative to data/templates)\")\n\ttemplateRenderCmd.Flags().String(\"path\", \"\", \"template path (absolute or relative to data/templates)\")\n\ttemplateRenderCmd.Flags().String(\"id\", \"\", \"block ID to render against\")\n\ttemplateSaveAsCmd.Flags().String(\"id\", \"\", \"source document block ID\")\n\ttemplateSaveAsCmd.Flags().String(\"name\", \"\", \"template name without extension\")\n\ttemplateSaveAsCmd.Flags().Bool(\"overwrite\", false, \"overwrite if exists\")\n\ttemplateCreateCmd.Flags().String(\"name\", \"\", \"template name without extension\")\n\ttemplateCreateCmd.Flags().String(\"data\", \"\", \"markdown content\")\n\ttemplateCreateCmd.Flags().String(\"file\", \"\", \"read content from file path (- for stdin)\")\n\ttemplateCreateCmd.Flags().Bool(\"overwrite\", false, \"overwrite if exists\")\n\n\trootCmd.AddCommand(templateCmd)","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/cli/cmd/template.go#L184-L220","documentation":"Returned by `resolveTemplateAbs` after `filepath.Rel(templatesBase, abs)` yields a relative path starting with `..` (or equal to `..`). This is a security guard preventing path traversal: the resolved absolute path must stay inside `data/templates/`, otherwise an attacker-controlled `--path` could read or write arbitrary files.","triggerScenarios":"Passing `--path ../../../etc/passwd`, `--path /etc/passwd` (absolute path outside the templates dir), or any value that, after `filepath.Clean`, resolves above `data/templates`. Symlinks inside the dir are not dereferenced by this check, but lexical escapes are blocked.","commonSituations":"User typos with leading `../`; tooling that concatenates untrusted input into `--path`; absolute paths intended for a different working directory.","solutions":["Use a plain template name or a path strictly under `data/templates/`, e.g. `--path sub/foo.md`.","If you genuinely need a file from elsewhere, copy it into `data/templates/` first, then reference it by its in-dir path.","Sanitize untrusted input by stripping leading `/` and any `..` segments before passing to the CLI."],"exampleFix":"// before\nsiyuan template get --path ../../shared/note.md\n// after\ncp ../../shared/note.md data/templates/shared-note.md && siyuan template get --path shared-note.md","handlingStrategy":"validation","validationCode":"// Pre-sanitize before calling resolveTemplateAbs-equivalent logic:\nclean := filepath.Clean(p)\nrel, err := filepath.Rel(templatesBase, clean)\nif err != nil || strings.HasPrefix(rel, \"..\") || rel == \"..\" {\n    return fmt.Errorf(\"path escapes templates dir: %s\", p)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never concatenate untrusted input into --path.","Prefer plain template names over filesystem paths.","Copy external files into data/templates/ first, then reference them in-dir."],"tags":["security","path-traversal","cli","template","validation"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}