Sep 4, 2026·7 min read·38 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.
A path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.