GitHub Advisoryadvisory · Go
GHSA-p23f-cm6q-2qp8 SiYuan MCP asset.upload Reads Arbitrary Absolute File Paths (Workspace Boundary Bypass)
MEDIUM
Official page ↗
- Ecosystem
- Go
- Packages
- github.com/siyuan-note/siyuan/kernel
- Severity
- Moderate
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N
- Weaknesses
- CWE-22
- Reviewed
- 2026-10-02
Affected packages
• Go github.com/siyuan-note/siyuan/kernel: < 0.0.0-20260813142104-b26a4a307b8a → fixed in 0.0.0-20260813142104-b26a4a307b8a
Description
Security Advisory — SiYuan MCP `asset.upload` Reads Arbitrary Absolute File Paths (Workspace Boundary Bypass)
| Field | Value |
|---|---|
| Disclosed by | joysinleung (`[email protected]`) |
| Report date | 2026-08-13 |
| Product | SiYuan (思源笔记) — `siyuan-note/siyuan` |
| Go module | `github.com/siyuan-note/siyuan/kernel` |
| Affected versions | `",
"files": "/Users/victim/.ssh/id_rsa,/Users/victim/.aws/credentials,/etc/passwd"
}
```
Handler flow:
1. `filepath.Abs("/Users/victim/.ssh/id_rsa")` → `/Users/victim/.ssh/id_rsa` (no `IsSubPath`/`IsSensitivePath` rejection).
2. `InsertLocalAssets` → `os.Open` → bytes copied into `/data/assets/...`.
3. The private key is now readable via the workspace file API / export / sync.
Impact
Confidentiality breach: arbitrary local file read (including SSH keys, cloud credentials, OS secrets) through the AI plane. Integrity/availability not directly impacted. Severity is moderated by the required user approval step, but the approval dialog does not reveal the real source path, so the user cannot make an informed decision.
Scope
Reachable only when the Agent/MCP surface is configured and the user approves the upload action. The boundary check is absent regardless of config — any approved upload reads outside the workspace.
Remediation
1. Add boundary enforcement in `assetUpload`: reject any entry where `!util.IsSubPath(util.WorkspaceDir, abs)` or `util.IsSensitivePath(abs)` (same checks used elsewhere).
2. Show the real source path in the confirmation dialog so the user can make an informed decision (currently the `LocalWrite` gate is action-category based and hides the specific path).
3. Mirror the `resolvePath` workspace-relative constraint already applied to the `file` / `unzip` tools.
> Note: patch authored against v3.8.0 source; not compiled into a full SiYuan release build. Provided for the maintainer to validate in CI.
---
Appendix: Suggested Patch (F10)
```diff
diff --git a/kernel/mcp/tools/asset.go b/kernel/mcp/tools/asset.go
index aaa..bbb 100644
--- a/kernel/mcp/tools/asset.go
+++ b/kernel/mcp/tools/asset.go
@@ -195,8 +195,16 @@ func assetUpload(args map[string]any) (CallToolResult, error) {
fileList := strings.Split(filesStr, ",")
for i, f := range fileList {
abs, err := filepath.Abs(strings.TrimSpace(f))
- if err != nil {
+ if err != nil {
return CallToolResult{}, err
}
+ // 边界校验:仅允许工作区内的资产,拒绝任意绝对路径越界读
+ if !util.IsSubPath(util.WorkspaceDir, abs) || util.IsSensitivePath(abs) {
+ ret.Code = -1
+ ret.Msg = fmt.Sprintf("asset path %s is outside the workspace or sensitive", abs)
+ return CallToolResult{}, fmt.Errorf("asset path outside workspace: %s", abs)
+ }
fileList[i] = abs
}
succMap, err := model.InsertLocalAssets(id, fileList, true)
```
Related
Weakness · CWE (1)
- CWE-22 Improper Limitation of a Pathname to a Restricted Directory weakness