Sep 4, 2026·7 min read·3 visits
Unauthenticated second-order SQL injection in SiYuan personal knowledge management system via malicious dynamic icon template rendering in Attribute Views.
CVE-2026-72807 is a second-order SQL injection vulnerability in SiYuan versions prior to v3.7.4. It resides in the dynamic evaluation of Attribute View (AV) template columns, which expose unsafe template functions. An attacker can exploit this by distributing a malicious SiYuan package that executes arbitrary SQL queries on the victim's local database.
SiYuan is a local-first personal knowledge management system that utilizes a structured SQLite database to organize document blocks, notebooks, and metadata. Within this ecosystem, Attribute Views (AV) provide a mechanism to query, filter, and render structured attributes associated with markdown document blocks. To enhance presentation capabilities, the rendering engine supports dynamic templates for specific elements, such as dynamic icons.
This rendering architecture exposes an attack surface via dynamic icon templates. Specifically, in versions of SiYuan prior to v3.7.4, the function responsible for processing dynamic icons, RenderDynamicIconContentTemplate, evaluated server-side Go templates using inputs stored within the documents themselves. Because these templates are executed locally within the context of the user's running SiYuan application, any embedded logic runs with the privileges of the active application instance.
The core vulnerability is classified under CWE-89 (Improper Neutralization of Special Elements used in an SQL Command) and manifests as a second-order SQL injection. An attacker can distribute malicious .sy documents or notebook packages containing crafted dynamic icon attributes. When a victim imports and views these documents, the local SiYuan kernel automatically renders the template, triggering the execution of arbitrary, unsanitized SQL commands directly against the underlying database.
The root cause of CVE-2026-72807 resides in the insecure design of the server-side template engine execution context. When rendering dynamic icon content, the application called RenderDynamicIconContentTemplate which initialized a Go template engine with custom delimiters. To provide data manipulation capabilities, the engine registered a broad suite of built-in and SQL-specific utility functions by executing sql.SQLTemplateFuncs(&tplFuncMap).
Among the registered utility functions, helper functions such as queryBlocks and querySpans were designed to allow templates to execute queries against document metadata. However, these functions did not use parameterized SQL statements. Instead, they relied on manual string substitution to replace the placeholder ? with raw string arguments passed to the template function:
(*templateFuncMap)["queryBlocks"] = func(stmt string, args ...string) (retBlocks []*Block) {
for _, arg := range args {
stmt = strings.Replace(stmt, "?", arg, 1)
}
retBlocks = SelectBlocksRawStmt(stmt, 1, 512)
return
}Because the string substitution performs direct interpolation without sanitizing special characters or enforcing database parameters, an attacker can break out of the SQL syntax. For example, passing a string that contains SQL control characters such as single quotes, semicolons, or comment indicators allows the injection of arbitrary SQL statements. Furthermore, the database execution context of these helper functions was not restricted to read-only operations, enabling complete control over the underlying SQLite database schema and records.
To understand the technical context, we compare the vulnerable implementation against the remediated code introduced in commit 0a176345e02a0d19bdc7762e50e0b92002087d20.
In the vulnerable version of kernel/model/template.go, the application registered all template utility functions, including direct SQL querying capabilities, within the dynamic rendering path:
// VULNERABLE
func RenderDynamicIconContentTemplate(content, id string) (ret string) {
// ...
goTpl := template.New("").Delims(".action{", "}")
tplFuncMap := filesys.BuiltInTemplateFuncs()
sql.SQLTemplateFuncs(&tplFuncMap) // Insecure: Registers raw SQL functions
goTpl = goTpl.Funcs(tplFuncMap)
// ...
}The patch addresses this by replacing the registration of raw SQL template functions with a restricted function map that only exposes non-critical filesystem utility functions:
// PATCHED
func RenderDynamicIconContentTemplate(content, id string) (ret string) {
// ...
goTpl := template.New("").Delims(".action{", "}")
tplFuncMap := dynamicIconTemplateFuncs() // Restricts functions to safe defaults
goTpl = goTpl.Funcs(tplFuncMap)
// ...
}
func dynamicIconTemplateFuncs() template.FuncMap {
return filesys.BuiltInTemplateFuncs()
}Additionally, the patch introduces validation mechanisms inside kernel/sql/database.go for contexts where SQL templates are still legitimately used. The function isReadonlyStmt acts as a gatekeeper, checking queries against structural limitations:
// PATCHED SQL Validation
func SQLTemplateFuncs(templateFuncMap *template.FuncMap) {
readonlyStmts := &sync.Map{}
isReadonlyStmt := func(stmt string) bool {
if _, ok := readonlyStmts.Load(stmt); ok {
return true
}
if CheckSingleStatement(stmt) != nil || CheckReadonlyStatement(stmt) != nil {
return false
}
readonlyStmts.Store(stmt, struct{}{})
return true
}
// ...
}Exploitation of CVE-2026-72807 requires a multi-stage delivery process due to its second-order nature. First, the attacker must construct a malicious notebook package or dynamic document containing an Attribute View. Within this Attribute View, the attacker configures a dynamic icon template using the Go template syntax delimiters .action{ and }.
// Conceptual payload within dynamic icon template field
.action{queryBlocks "SELECT * FROM blocks WHERE id = '?'" "1' UNION SELECT NULL, NULL, (SELECT password FROM users), ...--"}The target must then import this notebook or document into their local SiYuan application. This is typically achieved through social engineering, where an attacker hosts malicious public knowledge templates, themes, or shared documents.
Once imported, the SiYuan kernel parses the documents. When the victim navigates to a view that triggers the rendering of the dynamic icon, the kernel invokes RenderDynamicIconContentTemplate. This triggers the Go template engine, parses the injected .action{queryBlocks ...} statement, and executes the interpolated SQL command against the local SQLite database.
The impact of successful exploitation is substantial, particularly given SiYuan's architectural model as a local-first personal knowledge database. Because the application runs locally on the victim's operating system, the executing database contains the entirety of the user's personal wiki, private notes, configuration settings, and potential integration tokens.
Using SQL injection, an attacker can extract sensitive information across all notebooks. This includes reading arbitrary block data, extracting private metadata, or stealing database tables that contain application credentials or API keys. Since the raw database connection is shared, write capability enables unauthorized modifications.
Furthermore, the severity is reflected in the CVSS v4.0 base score of 8.8 (High). While the attack vector is network-based (due to remote distribution of malicious documents), the attack complexity is considered High because it relies on the victim importing and rendering the crafted package. Confidentiality and integrity impacts are both rated as High because an attacker can completely read and modify the underlying SQLite database structure.
The primary remediation for this vulnerability is upgrading SiYuan to version v3.7.4 or later. In this release, the developer completely isolates dynamic icon rendering from database access functions. If immediate upgrade is not possible, users must refrain from importing unverified .sy packages, templates, or notebooks from untrusted third-party sources.
While the patch successfully isolates the dynamic icon template context from database functions, security teams should evaluate the completeness of the database-level hardening. The isReadonlyStmt function uses a caching mechanism based on a sync.Map (readonlyStmts). Because the cache key is the fully interpolated SQL query, generating an infinite sequence of distinct queries could lead to unbounded memory growth, creating a minor denial-of-service vector.
Furthermore, the security of the SQL execution path in remaining templates relies entirely on CheckSingleStatement and CheckReadonlyStatement. If these functions utilize simplified regular expressions rather than a fully compliant SQLite SQL parser, they may be vulnerable to parser-differential bypasses. Attackers could utilize complex SQL syntax or nested expressions to execute write operations that circumvent the detection logic.
CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
siyuan siyuan-note | < 3.7.4 | 3.7.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-89 |
| Attack Vector | Network |
| CVSS v4.0 Score | 8.8 (High) |
| EPSS Score | 0.00199 (Percentile: 9.77%) |
| Exploit Status | No public PoC |
| CISA KEV Status | Not Listed |
| Impact | Arbitrary read/write database access |
The application constructs raw SQL commands using unsanitized template inputs, allowing modification of the command structure.
An authorization bypass vulnerability in SiYuan prior to v3.7.4 allows unauthenticated remote attackers to access rows, block IDs, and custom attributes of password-protected documents via the attribute view rendering endpoint.
SiYuan Note versions before v3.7.4 fail to enforce publish-access checks on several block API endpoints. This vulnerability allows anonymous readers or authorized accounts with low-privileged roles to retrieve sensitive document titles, ancestor block content snippets, reference text, and path metadata for publish-forbidden or password-protected documents by supplying target block IDs.
SiYuan before version 3.7.4 contains an authentication bypass vulnerability within its graph visualization API endpoints, allowing unauthenticated remote attackers to extract sensitive node metadata and content from password-protected documents.
SiYuan Note versions prior to v3.7.4 contain an information disclosure vulnerability in the `/api/asset/resolveAssetPath` endpoint. This endpoint returns absolute backend filesystem paths unmodified to CheckAuth-only requests. Low-privileged users or unauthenticated readers under publish mode can exploit this to leak the local directory layout, operating system username, and overall host deployment structure.
An access control vulnerability in the SiYuan personal knowledge management platform before version v3.7.4 exposes notebook encryption parameters to unauthenticated remote attackers. When the platform is configured in Publish Mode, specific API endpoints fail to enforce authorization checks. This access failure leaks key-derivation materials, password verifiers, and wrapped database keys to anonymous network clients.
A security vulnerability in the SiYuan local-first personal knowledge management system allows unauthenticated remote attackers to bypass logical boundary controls in publish (read-only) mode. By interacting with endpoints that lack proper publish-access validation, an attacker can disclose the application's internal database schemas and harvest block IDs across both public and private notebooks. This metadata leakage compromises the confidentiality of restricted documents and provides foundational information for targeted extraction.