Skip to content

GHSA-7m5h-w69j-qggg CVE-2026-40259 GO-2026-5229

SiYuan: Publish Reader Can Arbitrarily Delete Attribute View Files via `/api/av/removeUnusedAttributeView`

High Go
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

  1. Attacker browses published content containing an attribute view.
  2. Attacker extracts the data-av-id value from the page/DOM.
  3. Attacker sends a POST request to /api/av/removeUnusedAttributeView through the publish service.
  4. Publish proxy injects a valid RoleReader token.
  5. CheckAuth accepts the request.
  6. The handler passes the attacker-controlled avID to model.RemoveUnusedAttributeView.
  7. 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:

  1. Block publish/read-only users from this route.
  2. Require admin/write authorization.
  3. 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

PackageVulnerableFixed 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

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy 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
Is this in your code?

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