siyuan-note/siyuan · error
asset path is sensitive: %s
Error message
asset path is sensitive: %s
What it means
The MCP asset upload tool refuses to process an asset whose absolute path resolves to a sensitive location in the workspace (e.g. the data directory internals, config, or other protected paths checked by util.IsSensitivePath). This is a safety guard in validateAssetUploadPaths so MCP callers cannot read or overwrite critical workspace files by naming them as assets. The error is returned before any upload happens and aborts the whole call.
Source
Thrown at kernel/mcp/tools/asset.go:242
_, succFiles, failedFiles, err := model.InsertLocalAssets(id, fileList, true)
if err != nil {
return CallToolResult{Content: []ContentItem{{Type: "text", Text: "upload assets failed: " + err.Error()}}, IsError: true}, nil
}
return newAssetUploadToolResult(succFiles, failedFiles), nil
}
// validateAssetUploadPaths 将上传路径归一化为绝对路径,并拒绝敏感路径,
// 防止通过 AI 提示注入诱导上传本地凭据等敏感文件(如 SSH 私钥、云服务凭据)后外泄。
// 非敏感的工作区外绝对路径仍然允许上传,与 globalCopyFiles 等接受工作区外路径的接口保持一致。
func validateAssetUploadPaths(fileList []string) ([]string, error) {
for i, f := range fileList {
abs, err := filepath.Abs(strings.TrimSpace(f))
if err != nil {
return nil, err
}
if util.IsSensitivePath(abs) {
return nil, fmt.Errorf("asset path is sensitive: %s", abs)
}
fileList[i] = abs
}
return fileList, nil
}
func assetUnused(args map[string]any) (CallToolResult, error) {
items := model.UnusedAssets(true)
if len(items) == 0 {
return CallToolResult{Content: []ContentItem{{Type: "text", Text: "no unused assets found"}}}, nil
}
var sb strings.Builder
sb.WriteString(fmt.Sprintf("Unused assets (%d):\n\n", len(items)))
for _, item := range items {
sb.WriteString(fmt.Sprintf("- %s (%s)\n", item.Item, item.Name))
}
return CallToolResult{Content: []ContentItem{{Type: "text", Text: sb.String()}}}, nil
}View on GitHub (pinned to 8641553a1f)
Solutions
- Pick an asset source path that is not a sensitive/protected workspace path; place the file in a normal assets or user directory.
- Check which paths util.IsSensitivePath treats as protected (kernel/util) and verify your absolute path against them before calling the tool.
- If the intent was to read/modify protected workspace data, use the dedicated kernel API instead of the MCP asset upload tool.
- Log the resolved absolute path shown in the error and correct the input argument accordingly.
Example fix
// before
await mcp.call("assetUpload", { files: [workspaceDir + "/conf/conf.json"] });
// after
await mcp.call("assetUpload", { files: ["/home/user/pictures/logo.png"] }); Defensive patterns
Strategy: validation
Validate before calling
const path = require('path');
const protectedDirs = ['conf', 'temp', 'history', 'snapshots'];
function isSafeAssetPath(p, workspaceDir) {
const abs = path.resolve(p);
if (!abs.startsWith(path.resolve(workspaceDir) + path.sep)) return false;
const rel = path.relative(workspaceDir, abs);
return !protectedDirs.some(d => rel === d || rel.startsWith(d + path.sep));
}
if (!isSafeAssetPath(files[i], workspaceDir)) throw new Error('sensitive asset path: ' + files[i]); Type guard
function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; } Try / catch
try {
await mcp.call("assetUpload", { files });
} catch (e) {
if (String(e.message).startsWith("asset path is sensitive")) {
// relocate file outside protected dirs and retry
}
} Prevention
- Source assets from user/content directories, never workspace config or system dirs
- Resolve to absolute paths and compare against the sensitive-path list before calling
- Keep an allowlist of asset source directories in automation scripts
When it happens
Trigger: Calling the MCP assetUpload tool with a file path argument that, after filepath.Abs, matches util.IsSensitivePath — e.g. a path pointing at the workspace config dir, temp/backup internals, or any protected location. A path like '<workspace>/conf/conf.json' or another protected path triggers it.
Common situations: An MCP client (LLM agent) hallucinating or guessing a path that overlaps protected workspace directories; a caller using the workspace root itself or config paths as the source of an asset; automation scripts built with relative paths that resolve into protected dirs.
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
- invalid archive entry path [%s]
- archive entry resolves outside destination [%s]
- marketplace package contains an invalid path
- path escapes workspace: %s
- symlink escapes workspace: %s
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/603df1b276538284.
Report an issue: GitHub.