GHSA-7m5h-w69j-qggg CVE-2026-40259 GO-2026-5229
SiYuan: Publish Reader Can Arbitrarily Delete Attribute View Files via `/api/av/removeUnusedAttributeView`
- Severity
- 8.1 / 10
- High · CVSS 3.1
- Exploit chance (EPSS)
- 0.40%
- Chance of exploitation in the next 30 days. Higher than 34.24% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-285 Improper Authorization
- Fix
0.0.0-20260407035653-2f416e5253f1- Upgrade github.com/siyuan-note/siyuan/kernel to this version or later
Description
Summary
An authenticated publish-service reader can invoke /api/av/removeUnusedAttributeView and cause persistent deletion of arbitrary attribute view (AV) definition files from the workspace.
The route is protected only by generic CheckAuth, which accepts publish RoleReader requests. The handler forwards a caller-controlled id directly into a model function that deletes data/storage/av/<id>.json without verifying either:
- that the caller is allowed to perform write/destructive actions; or
- that the target AV is actually unused.
This is a persistent integrity and availability issue reachable from the publish surface.
Root Cause
1. Publish users are issued a RoleReader JWT
- kernel/model/auth.go
ClaimsKeyRole: RoleReader,
2. The publish reverse proxy forwards that token upstream
- kernel/server/proxy/publish.go
- kernel/server/proxy/publish.go
3. CheckAuth accepts RoleReader
- kernel/model/session.go
if role := GetGinContextRole(c); IsValidRole(role, []Role{
RoleAdministrator,
RoleEditor,
RoleReader,
}) {
c.Next()
return
}
4. The route is exposed with CheckAuth only
- kernel/api/router.go
ginServer.Handle("POST", "/api/av/removeUnusedAttributeView", model.CheckAuth, removeUnusedAttributeView)
There is no CheckAdminRole and no CheckReadonly.
5. The handler forwards attacker-controlled id directly to the delete sink
- kernel/api/av.go
avID := arg["id"].(string)
model.RemoveUnusedAttributeView(avID)
6. The model deletes the AV file unconditionally
- kernel/model/attribute_view.go
func RemoveUnusedAttributeView(id string) {
absPath := filepath.Join(util.DataDir, "storage", "av", id+".json")
if !filelock.IsExist(absPath) {
return
}
...
if err = filelock.RemoveWithoutFatal(absPath); err != nil {
...
return
}
IncSync()
}
Crucially, this function does not verify that the supplied AV is actually unused. The name of the function suggests a cleanup helper, but the implementation is really "delete AV file by id if it exists".
Attack Prerequisites
- Publish service enabled
- Attacker can access the publish service
- If publish auth is enabled, attacker has valid publish-reader credentials
- Attacker knows an
avID
Obtaining avID
avID is not secret. It is exposed extensively in frontend markup as data-av-id.
Examples:
- app/src/protyle/render/av/render.ts
- app/src/protyle/render/av/layout.ts
- app/src/protyle/render/av/groups.ts
Any publish-visible database/attribute view can therefore disclose a valid avID to the attacker.
Exploit Path
- Attacker browses published content containing an attribute view.
- Attacker extracts the
data-av-idvalue from the page/DOM. - Attacker sends a POST request to
/api/av/removeUnusedAttributeViewthrough the publish service. - Publish proxy injects a valid
RoleReadertoken. CheckAuthaccepts the request.- The handler passes the attacker-controlled
avIDtomodel.RemoveUnusedAttributeView. - The backend deletes
data/storage/av/<avID>.json.
Proof of Concept
Request:
POST /api/av/removeUnusedAttributeView HTTP/1.1
Host: <publish-host>:<publish-port>
Content-Type: application/json
Authorization: Basic <publish-account-creds-if-enabled>
{
"id": "<exposed-data-av-id>"
}
Expected result:
- HTTP 200
- backend increments sync state
- the target attribute view file is removed from
data/storage/av/ - published and local workspace behavior for that AV becomes broken until restored from history or recreated
Impact
This gives a low-privileged publish reader a destructive persistent write primitive against workspace data.
Practical consequences include:
- deletion of live attribute view definitions
- corruption/breakage of published database views
- breakage of local workspace rendering and AV-backed relationships
- operational disruption until restore or manual repair
The bug affects integrity and availability, not merely UI state.
Recommended Fix
At minimum:
- Block publish/read-only users from this route.
- Require admin/write authorization.
- Re-validate that the target AV is actually unused before deletion.
Safe router fix:
ginServer.Handle("POST", "/api/av/removeUnusedAttributeView",
model.CheckAuth,
model.CheckAdminRole,
model.CheckReadonly,
removeUnusedAttributeView,
)
And inside the model or handler, reject deletion unless the target id is present in UnusedAttributeViews(...).
Affected versions
Go
| Package | Vulnerable | Fixed in |
|---|---|---|
| github.com/siyuan-note/siyuan/kernel | < 0.0.0-20260407035653-2f416e5253f1 |
0.0.0-20260407035653-2f416e5253f1 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
github.com/siyuan-note/siyuan/kernel Go → 0.0.0-20260407035653-2f416e5253f1
- go
go get github.com/siyuan-note/siyuan/kernel@v0.0.0-20260407035653-2f416e5253f1 && go mod tidy
Severity breakdown
CVSS 3.1 8.1
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- Low
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- None
- Integrity
- High
- Availability
- High
Weakness
CWE-285: Improper Authorization
The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.
How to prevent it
- Architecture and Design: Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) to enforce the roles at the appropriate boundaries. Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
- Architecture and Design: Ensure that you perform access control checks related to your business logic. These checks may be different than the access control checks that you apply to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor.
- Architecture and Design: Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid. For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
- Architecture and Design: For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page. One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
- System Configuration, Installation: Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-xp3q-r38w-vgqm SiYuan: The publish filter for local storage returns the administrator's entire storage map with only three keys sanitized | Medium | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-9cqf-hhrq-7v45 SiYuan: getAttributeViewSearchTarget returns database row content to anonymous readers with no publish-access check, reopening the class closed one day earlier at the adjacent route | High | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-57v5-wqx3-cgj4 SiYuan: Database view structure (all view names, layout types and per-field visibility) is returned to anonymous readers by /api/av/getAttributeViewFieldViews | Medium | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-4wwp-f6gw-6qm5 SiYuan: TLS Private Keys Readable via getFile (Incomplete Blocklist) | High | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-3cm4-ccvw-6xr6 SiYuan: /history/*path and /repo/diff/*path potentially exposing historical snapshots of data/.siyuan/publishAccess.json and data/templates/* | Medium | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-x8gv-g2g3-65fj SiYuan Agent Tools SSRF via DNS-Rebinding TOCTOU (Bypass of CheckHostSSRF) | High | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-p23f-cm6q-2qp8 SiYuan MCP asset.upload Reads Arbitrary Absolute File Paths (Workspace Boundary Bypass) | Medium | Also affects github.com/siyuan-note/siyuan/kernel |
| GHSA-rpx2-p6hp-x5gj SiYuan: Missing consistency check between packageName and repoURL/repoHash in bazaar package install allows overwriting an existing, trusted plugin | Medium | Also affects github.com/siyuan-note/siyuan/kernel |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor