siyuan-note/siyuan · error

access to sensitive workspace file is forbidden: %s

Error message

access to sensitive workspace file is forbidden: %s

What it means

`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.

Source

Thrown at kernel/mcp/tools/file.go:105

func resolvePath(rel string) (string, error) {
	rel = filepath.Clean(strings.ReplaceAll(rel, "/", string(os.PathSeparator)))
	abs := filepath.Join(util.WorkspaceDir, rel)
	if !gulu.File.IsSubPath(util.WorkspaceDir, abs) {
		return "", fmt.Errorf("path escapes workspace: %s", rel)
	}
	// 拒绝加密笔记本目录:MCP 文件工具不能读写加密 box 下的文件(防止密文泄漏或明文破坏加密格式)
	if boxID, encrypted := rejectEncryptedPath(abs); encrypted {
		return "", fmt.Errorf("path belongs to encrypted notebook [%s]: %s", boxID, rel)
	}
	// 防止 symlink 逃逸工作区:解析符号链接后再次检查
	if resolved := util.ResolveLongestExistingParent(abs); resolved != abs && !gulu.File.IsSubPath(util.WorkspaceDir, resolved) {
		return "", fmt.Errorf("symlink escapes workspace: %s", rel)
	}
	// 禁止访问敏感文件(conf/conf.json、data/snippets/conf.json、data/templates、data/.siyuan/publishAccess.json),
	// 与 HTTP 文件 API 共用同一黑名单(见 kernel/util/path_guard.go 的 IsForbiddenAbsPath)
	if util.IsForbiddenAbsPath(abs) {
		return "", fmt.Errorf("access to sensitive workspace file is forbidden: %s", rel)
	}
	return abs, nil
}

// rejectEncryptedPath 检查路径是否属于加密笔记本(含 symlink 绕过),返回 boxID 和是否为加密 box。
func rejectEncryptedPath(absPath string) (boxID string, encrypted bool) {
	boxID = model.EncryptedRawPathBoxID(absPath)
	return boxID, boxID != ""
}

func fileList(args map[string]any) (CallToolResult, error) {
	p, _ := args["path"].(string)
	if p == "" {
		return CallToolResult{Content: []ContentItem{{Type: "text", Text: "path is required"}}, IsError: true}, nil
	}
	dir, err := resolvePath(p)
	if err != nil {
		return CallToolResult{Content: []ContentItem{{Type: "text", Text: err.Error()}}, IsError: true}, nil

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Use the dedicated SiYuan APIs/UI for editing configuration, snippets, templates, and publish access — not the MCP file tool.
  2. If the intent was a normal note, correct the `path` to point at a permitted data file.
  3. Treat this guard as authoritative; do not attempt to bypass it.
Defensive patterns

Strategy: validation

Validate before calling

// Reuse the shared blacklist before calling the file tool.
if util.IsForbiddenAbsPath(abs) {
    return "", fmt.Errorf("access to sensitive workspace file is forbidden")
}

Prevention

When it happens

Trigger: A file tool `path` argument resolves to one of the blacklisted sensitive files or directories; `IsForbiddenAbsPath(abs)` returns true.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/9ec997bd3fea3ddf. Report an issue: GitHub.