Sep 4, 2026·8 min read·2 visits
Inconsistent authorization controls in SiYuan prior to v3.7.4 permitted low-privilege or anonymous readers to bypass REST API security filters and download sensitive templates, snippets, widgets, and ZIP backups by accessing their static routes directly.
A detailed technical breakdown of CVE-2026-72796 (GHSA-fgmr-7w36-9qfq), an access control bypass vulnerability in the SiYuan personal knowledge management system. Prior to version 3.7.4, inconsistent authorization checks between dynamic API endpoints and static file routes allowed authenticated low-privilege readers or anonymous public users to read sensitive files, templates, snippets, and export directories.
SiYuan is a privacy-first, self-hosted personal knowledge management system that utilizes a local-first architecture while providing web-facing components for remote access and publishing. Prior to version 3.7.4, the application's backend server suffered from an authorization inconsistency in its routing logic. While dynamic REST API endpoints were protected by rigorous, role-based access control filters, static-file route groups bypassed these fine-grained authorization policies.
This flaw is classified under CWE-862 (Missing Authorization). The system exposed several sensitive static asset directories directly via the Gin Web Framework's static routing engine. Because these routes only verified the presence of basic authentication or a reader token, low-privilege readers and anonymous users could access administrative folders. This allowed the unauthorized disclosure of document templates, customized widgets, snippet files, and static export archives.
The attack surface is exposed via the web interface of any network-accessible SiYuan instance. An attacker with a valid low-privilege reader session, or an unauthenticated user if the instance is configured in public-publish mode, can bypass REST-level security restrictions. The impact is limited to confidentiality, enabling unauthorized retrieval of sensitive configuration parameters, custom script payloads, and potentially full database export backups.
The vendor mitigated this vulnerability in version 3.7.4 by implementing a dual-layer defensive control. First, sensitive static endpoints were restricted to verified administrators. Second, a dynamic reference-validation mechanism was introduced to parse Markdown Abstract Syntax Trees (ASTs) and dynamically authorize static assets only if they are actively referenced within a public document.
The SiYuan backend server uses the Gin Web Framework in Go to handle HTTP routing. The application registers dynamic API endpoints and static file directories within the same server initialization file, located at kernel/server/serve.go. In the vulnerable versions, the routing architecture created two separate paths for accessing workspace data: dynamic REST query endpoints and static file-serving groups.
The primary flaw lies in the inconsistent application of middleware across these routing paths. The REST API endpoints enforced strict, role-based authorization checks, validating that the requesting user possessed the administrator role before serving resources like templates or snippets. Conversely, static file route groups—such as /templates/*, /export/*, /widgets/*, /emojis/*, and /snippets/*—were registered using only the general model.CheckAuth middleware.
The model.CheckAuth middleware is designed to verify that the requesting client possesses a valid session, token, or cookie. However, in anonymous public-sharing or reader mode, this middleware considers low-privilege readers as authorized entities. Because the static route configuration mapped these entire directories to the file system under model.CheckAuth, the application failed to verify if the requesting entity had the specific administrator privileges required to access the underlying directories.
In addition to the missing authorization controls, the registration of these static routes lacked robust path-traversal validation. For example, the handler for /snippets/ utilized naive concatenation with filepath.Join and performed simple substring validation. While the system attempted to prevent directory traversal, it lacked central normalization, creating risk when handling complex URLs or symbolic links within the data directory.
In versions prior to 3.7.4, the routing configuration in kernel/server/serve.go did not include administrative verification checks for static resource groups. The following code snippet illustrates the insecure configuration where the entire templates and widgets directories were exposed using Gin's standard static router grouping:
// Pre-patch code in kernel/server/serve.go
func serveWidgets(ginServer *gin.Engine) {
// Insecure: only verifies basic auth, exposing all widgets
widgets := ginServer.Group("/widgets/", model.CheckAuth)
widgets.Static("", filepath.Join(util.DataDir, "widgets"))
}
func serveTemplates(ginServer *gin.Engine) {
// Insecure: exposes all user-defined templates without admin verification
templates := ginServer.Group("/templates/", model.CheckAuth)
templates.Static("", filepath.Join(util.DataDir, "templates"))
}The patch in commit 34be6c0bb0739d5b8e99ecc0cbfb474abb16230d introduces strict route separation and implements custom static handlers. In the patched code, access to sensitive templates and exports is strictly bound to administrative accounts, while a reference-checking mechanism secures widgets:
// Patched code in kernel/server/serve.go
func serveTemplates(ginServer *gin.Engine) {
// Secure: admin-only check is now enforced on templates
templates := ginServer.Group("/templates/", model.CheckAuth, model.CheckAdminRole)
registerStaticFileHandlers(templates, filepath.Join(util.DataDir, "templates"), true, nil)
}The custom handler function registerStaticFileHandlers replaces direct Gin file mapping. It enforces normalization of path requests through cleanStaticRelativePath, which filters out malicious traversal components prior to executing any file system read operation:
func cleanStaticRelativePath(requestPath string) (string, bool) {
requestPath = strings.TrimPrefix(requestPath, "/")
relativePath := filepath.Clean(filepath.FromSlash(requestPath))
// Prevent directory traversal and escape sequences
if filepath.IsAbs(relativePath) || filepath.VolumeName(relativePath) != "" ||
relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(os.PathSeparator)) {
return "", false
}
return relativePath, true
}The implementation of the cleanStaticRelativePath function combined with model.CheckAdminRole effectively remediates both directory traversal risks and the access control bypass on templates. For standard assets like emojis or widgets that must remain readable by guests, the patch implements a dynamic validation filter discussed in the mitigation section.
To exploit this vulnerability, an attacker must first establish a network connection to the target SiYuan web interface. The exploit does not require administrator privileges. Depending on the server configuration, the threat actor needs either a low-privilege reader token (if the server requires basic authentication) or zero authentication (if the instance is running in anonymous public-publish mode).
The attack relies on requesting static paths directly rather than querying the REST API endpoints. An administrator might block a regular reader from retrieving document templates via the standard API interface. However, the attacker bypasses this restriction by making a direct GET request targeting the static directory alias, for instance:
curl -i -H "Authorization: Token <low_privilege_reader_token>" \
"http://siyuan-target.local:6806/templates/confidential-template.md"Because the server did not validate whether the requested resource was linked to a public page, an attacker can brute-force common names of templates, custom snippets, and widgets. If an administrator previously exported the workspace database, the resulting file is saved in the static export directory. The attacker can download the export file by predicting or guessing its name, bypassing administrative REST controls:
curl -O "http://siyuan-target.local:6806/export/workspace_backup.zip"The primary consequence of this vulnerability is the unauthorized disclosure of sensitive data. Because templates, export directories, and snippets can contain proprietary system configurations, API keys, or private notes, exposing these directories results in a serious breach of confidentiality. An attacker cannot use this vulnerability to write or modify server files, preserving the integrity of the data store.
In the context of CVSS v3.1, this vulnerability achieves a base score of 5.8 (Medium), with a vector of CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N. The scope parameter is marked as Changed (S:C) because the path-based authorization bypass permits transition from the restricted application-level sandbox directly to raw filesystem asset directories.
Currently, this vulnerability has an EPSS score of 0.00257 (0.26%), indicating a low overall probability of exploitation in wild campaigns within a 30-day window. It is not currently listed in CISA's Known Exploited Vulnerabilities (KEV) catalog, nor is it associated with known active ransomware frameworks. However, the ease of replication using single-line HTTP requests highlights the risk to self-hosted instances exposed directly to the public internet.
The definitive remediation for CVE-2026-72796 is upgrading the SiYuan application to version 3.7.4 or later. In version 3.7.4, the developers refactored the routing subsystem to require model.CheckAdminRole on all sensitive directories including /templates/ and /export/. For containerized deployments, administrators should update their Docker configurations to fetch the latest official image tag.
For static directories that must remain accessible to public readers (such as /widgets/ and /emojis/), the vendor implemented a dynamic reference-validation mechanism. This engine parses the Markdown Abstract Syntax Tree (AST) of all published documents using the Lute engine. It extracts active widget and emoji references, dynamically adding them to a whitelist cache. When a reader requests a static widget, the server checks if that widget is in the whitelist, returning 403 Forbidden if it is not actively referenced.
If upgrading immediately is not feasible, administrators must reduce the exposed attack surface through configuration hardening. First, disable public publish mode and restrict the instance behind an authentication proxy or a private network segment. Second, manually inspect and clean the temp/export directory located in the application's workspace path to ensure no historical exports or sensitive zip archives remain readable on disk.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 |
| Attack Vector | Network |
| CVSS Score | 5.8 (Medium) |
| EPSS Score | 0.00257 (17.14th percentile) |
| Impact | Confidentiality |
| Exploit Status | Proof-of-Concept |
| KEV Status | Not Listed |
An unauthenticated remote shutdown vulnerability exists in the Microsoft TypeSpec Spector mock server. Due to missing authentication on critical administrative routes and binding to all network interfaces, any remote attacker can shut down the mock server.
CVE-2026-75858 is a critical authorization bypass vulnerability in CodeWhale's interactive execution tools, allowing silent, unprompted execution of model-supplied Python and shell commands on the host machine. The defect affects versions between 0.8.41 and 0.8.64, bypassing any configured approval policies via indirect prompt injection.
CVE-2026-75911 is a configuration injection and remote code execution vulnerability in CodeWhale. Unsafe merging of repository-level TOML configuration files allows malicious repositories to silently enable shell tool registration and inject prompts, forcing the integrated LLM agent to execute arbitrary host commands.
An improper link resolution vulnerability (CWE-59) in the image_analyze tool of CodeWhale allows remote attackers to traverse directories (CWE-22) and leak sensitive local files via symlink manipulation.
A prototype pollution vulnerability exists in the toml-node library (by BinaryMuse) in versions prior to 4.1.2. The flaw arises from inconsistent internal tracking of parsed paths (comma-joined vs. dot-joined serialization) combined with lack of object ownership validation during recursive dictionary descent (scalar descent). This allows unauthenticated remote attackers to modify base object structures by crafting malicious TOML documents containing conflicting duplicate table paths or nested references.
An unauthenticated SQL injection and SQL execution vulnerability in SiYuan allows remote attackers to compromise the integrity and confidentiality of the asset database. The flaw exists due to string concatenation in regular expression searches and a complete lack of authorization checks on raw SQL querying pathways under default configurations. Attackers can leverage this vulnerability to exfiltrate database contents, manipulate index records, or access cross-notebook contents without any valid credentials.