Skip to main content
Vulnerability Database/CVE-2026-101091

CVE-2026-101091: SiYuan SQL Injection Vulnerability

CVE-2026-101091 is a SQL injection vulnerability in SiYuan that allows attackers to execute malicious SQL statements through crafted documents. This post covers the technical details, affected versions, and mitigation steps.

Published:

CVE-2026-101091 Overview

CVE-2026-101091 is a SQL injection vulnerability [CWE-89] in SiYuan, a personal knowledge management application, affecting all versions before v3.8.4. The flaw resides in the block query embed feature, which fails to validate that SQL statements executed against siyuan.db are read-only. Attackers craft malicious .sy documents containing non-read-only SQL statements that execute automatically during background indexing, rendering, or export operations. No authentication is required, and the previous check based on searching for the select substring could be bypassed using comments or subqueries.

Critical Impact

Unauthenticated attackers can execute arbitrary SQL statements against the SiYuan database by tricking a user into opening or importing a crafted .sy document, enabling data tampering and integrity loss.

Affected Products

  • SiYuan versions before v3.8.4
  • The kernel/model/index.go block indexing path
  • The kernel/sql/block_query.go raw block query execution path

Discovery Timeline

  • 2026-09-28 - CVE-2026-101091 published to NVD
  • 2026-09-29 - Last updated in NVD database

Technical Details for CVE-2026-101091

Vulnerability Analysis

SiYuan supports embed blocks whose contents are populated by executing a SQL query against the local siyuan.db database. Before v3.8.4, the kernel validated these queries by checking whether the lowercased statement contained the substring select. This weak filter is trivially bypassed. An attacker can prefix a destructive statement with an SQL comment that contains select, or wrap it in a subquery, and the check will pass.

Because embed block scripts originate from document content, they are untrusted input. The vulnerable statements execute automatically during background indexing, note rendering, and export flows, so no user interaction with the embed block itself is required beyond opening a crafted .sy file. The result is unauthenticated SQL execution against the local database.

Root Cause

The root cause is improper neutralization of special elements used in an SQL command [CWE-89]. The pre-patch guard performed a substring match for select rather than parsing the statement and enforcing a single, read-only query. Multiple call sites that forwarded raw SQL to db.Query did not share a common validator, so any path missing the check became an injection sink.

Attack Vector

An attacker distributes a malicious .sy document (for example, via a shared workspace, template, or import) containing embed blocks with crafted SQL. When the victim opens, indexes, renders, or exports the document, SiYuan executes the attacker-controlled statement against siyuan.db under the local user's context. Exploitation requires network-delivered content and user interaction to open the document.

go
// Patch: kernel/model/index.go — replace substring check with strict validator
-		if !strings.Contains(strings.ToLower(stmt), "select") {
+		// Embed block scripts come from document content and are untrusted:
+		// must be validated as a single read-only query. A "contains select"
+		// check can be bypassed by comments or subqueries.
+		if err := sql.CheckReadonlyBlockQueryStatement(stmt, embedBlock.Box); nil != err {
+			logging.LogWarnf("skip non-readonly embed block [%s] script: %s", embedBlock.ID, err)
 			continue
 		}

Source: SiYuan commit e8ace0c

go
// Patch: kernel/sql/block_query.go — central guard on every raw SQL exit
+func checkRawBlockQueryStmt(stmt, boxID string) bool {
+	if err := CheckReadonlyBlockQueryStatement(stmt, boxID); nil != err {
+		trimmed := strings.TrimSpace(stmt)
+		if "" != trimmed && !strings.HasPrefix(trimmed, "//!js") {
+			logging.LogWarnf("sql query [%s] rejected as non-readonly: %s", stmt, err)
+		}
+		return false
+	}
+	return true
+}

 func SelectBlocksRawStmtArgs(stmt string, args []any, limit int) (ret []*Block) {
+	if !checkRawBlockQueryStmt(stmt, "") {
+		return
+	}
 	rows, err := query(stmt, args...)

Source: SiYuan commit e8ace0c

Detection Methods for CVE-2026-101091

Indicators of Compromise

  • SiYuan kernel log entries containing skip non-readonly embed block or rejected as non-readonly, indicating rejected malicious embed queries after patching.
  • Unexpected modifications to siyuan.db such as new, altered, or deleted rows in block tables outside of normal editing activity.
  • .sy documents originating from external sources containing embed blocks whose SQL includes keywords like UPDATE, DELETE, INSERT, ATTACH, or PRAGMA.

Detection Strategies

  • Statically scan imported .sy files for embed block SQL statements that are not single read-only queries.
  • Monitor SiYuan process behavior for unexpected writes to siyuan.db outside interactive editing sessions.
  • Review kernel warning logs after opening or importing untrusted notebooks to identify rejected statements.

Monitoring Recommendations

  • Track SiYuan installations by version and alert on any host running a release earlier than v3.8.4.
  • Audit workspaces that ingest shared or third-party notebook templates and log the source of every imported .sy file.
  • Baseline siyuan.db file size and last-modified timestamps to flag anomalous change patterns.

How to Mitigate CVE-2026-101091

Immediate Actions Required

  • Upgrade all SiYuan instances to v3.8.4 or later, which enforces read-only validation on every block query execution path.
  • Do not open or import .sy documents from untrusted sources until the upgrade is applied.
  • Back up existing siyuan.db databases before applying updates so integrity can be verified against a known-good state.

Patch Information

The fix is delivered in SiYuan v3.8.4 via commit e8ace0c89182c7ee1a1298ff2a849bb6a83dfdec. It introduces CheckReadonlyBlockQueryStatement and a shared checkRawBlockQueryStmt guard invoked by every code path that forwards raw SQL to db.Query, replacing the bypassable strings.Contains(..., "select") check. See the GitHub Security Advisory GHSA-67p9-hm94-xwf3 and the VulnCheck advisory for full details.

Workarounds

  • Restrict .sy document imports to trusted authors and remove embed blocks from any externally sourced notebooks before opening them.
  • Run SiYuan under a least-privileged user account with the database stored on a filesystem that supports snapshot-based rollback.
  • Disable or avoid triggering export and re-indexing operations on notebooks of unknown provenance until upgrading.
bash
# Verify installed SiYuan version and upgrade path
siyuan --version
# Expected output should be v3.8.4 or later

# Linux example: replace an older AppImage with the patched release
chmod +x SiYuan-linux-3.8.4.AppImage
mv SiYuan-linux-3.8.4.AppImage /opt/siyuan/SiYuan.AppImage

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.