{"record":{"id":"9ec997bd3fea3ddf","repo":"siyuan-note/siyuan","slug":"access-to-sensitive-workspace-file-is-forbidden","errorCode":null,"errorMessage":"access to sensitive workspace file is forbidden: %s","messagePattern":"access to sensitive workspace file is forbidden: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/file.go","lineNumber":105,"sourceCode":"\nfunc resolvePath(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\t// 拒绝加密笔记本目录：MCP 文件工具不能读写加密 box 下的文件（防止密文泄漏或明文破坏加密格式）\n\tif boxID, encrypted := rejectEncryptedPath(abs); encrypted {\n\t\treturn \"\", fmt.Errorf(\"path belongs to encrypted notebook [%s]: %s\", boxID, rel)\n\t}\n\t// 防止 symlink 逃逸工作区：解析符号链接后再次检查\n\tif resolved := util.ResolveLongestExistingParent(abs); resolved != abs && !gulu.File.IsSubPath(util.WorkspaceDir, resolved) {\n\t\treturn \"\", fmt.Errorf(\"symlink escapes workspace: %s\", rel)\n\t}\n\t// 禁止访问敏感文件（conf/conf.json、data/snippets/conf.json、data/templates、data/.siyuan/publishAccess.json），\n\t// 与 HTTP 文件 API 共用同一黑名单（见 kernel/util/path_guard.go 的 IsForbiddenAbsPath）\n\tif util.IsForbiddenAbsPath(abs) {\n\t\treturn \"\", fmt.Errorf(\"access to sensitive workspace file is forbidden: %s\", rel)\n\t}\n\treturn abs, nil\n}\n\n// rejectEncryptedPath 检查路径是否属于加密笔记本（含 symlink 绕过），返回 boxID 和是否为加密 box。\nfunc rejectEncryptedPath(absPath string) (boxID string, encrypted bool) {\n\tboxID = model.EncryptedRawPathBoxID(absPath)\n\treturn boxID, boxID != \"\"\n}\n\nfunc fileList(args map[string]any) (CallToolResult, error) {\n\tp, _ := args[\"path\"].(string)\n\tif p == \"\" {\n\t\treturn CallToolResult{Content: []ContentItem{{Type: \"text\", Text: \"path is required\"}}, IsError: true}, nil\n\t}\n\tdir, err := resolvePath(p)\n\tif err != nil {\n\t\treturn CallToolResult{Content: []ContentItem{{Type: \"text\", Text: err.Error()}}, IsError: true}, nil","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mcp/tools/file.go#L87-L123","documentation":"`resolvePath` found the resolved path matches `util.IsForbiddenAbsPath` — a shared blacklist (with the HTTP file API) covering sensitive workspace files such as `conf/conf.json`, `data/snippets/conf.json`, `data/templates`, and `data/.siyuan/publishAccess.json`. The MCP file tool must not read or overwrite these configuration/security files.","triggerScenarios":"A file tool `path` argument resolves to one of the blacklisted sensitive files or directories; `IsForbiddenAbsPath(abs)` returns true.","commonSituations":"Attempting to read or overwrite `conf/conf.json` (which holds auth/settings secrets), the publish-access control file, or the templates directory via the generic file tool instead of the dedicated, validated endpoints.","solutions":["Use the dedicated SiYuan APIs/UI for editing configuration, snippets, templates, and publish access — not the MCP file tool.","If the intent was a normal note, correct the `path` to point at a permitted data file.","Treat this guard as authoritative; do not attempt to bypass it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Reuse the shared blacklist before calling the file tool.\nif util.IsForbiddenAbsPath(abs) {\n    return \"\", fmt.Errorf(\"access to sensitive workspace file is forbidden\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Edit configuration/snippets/templates/publish-access via their dedicated APIs only.","Keep file-tool paths pointed at ordinary note data.","Treat the blacklist as authoritative."],"tags":["mcp","file","security","sensitive-file","hardening"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}