Mar 17, 2026·6 min read·4 visits
A bypass in SiYuan's SVG sanitizer allows unauthenticated attackers to achieve reflected XSS by injecting data:text/xml URIs. This can lead to session hijacking, data exfiltration, and potential RCE in desktop deployments.
GHSA-4MX9-3C2H-HWHG represents a critical reflected Cross-Site Scripting (XSS) vulnerability in the SiYuan personal knowledge management system. The flaw stems from an incomplete blocklist in the application's SVG sanitizer, allowing attackers to execute arbitrary JavaScript by embedding malicious data URIs in the unauthenticated dynamic icon generation endpoint.
GHSA-4MX9-3C2H-HWHG is a critical reflected Cross-Site Scripting (XSS) vulnerability in the SiYuan personal knowledge management system. This flaw exists within the /api/icon/getDynamicIcon endpoint, which serves dynamic icon content without requiring user authentication. The vulnerability represents the third documented bypass of the original CVE-2026-29183 fix, underscoring the inherent difficulty of using blocklists for input sanitization.
The application attempts to neutralize malicious SVG content using the SanitizeSVG function. This function employs a blocklist strategy to restrict specific MIME types within data: URIs. While the blocklist successfully mitigates payloads using text/html and image/svg+xml, it fails to account for alternative XML-based MIME types that browsers natively parse and execute.
Modern web browsers, including Chromium, process data:text/xml and data:application/xml payloads as standard XML documents. When these documents contain embedded SVG elements with active event handlers, the browser executes the defined JavaScript within the context of the application's origin. This parsing behavior bypasses the restrictive filters and results in arbitrary script execution when a user interacts with the crafted link.
The vulnerability originates in the kernel/util/misc.go file, specifically within the SanitizeSVG function. This function analyzes the href attributes of <a> tags embedded in the user-supplied content parameter. The validation logic checks if the URI begins with data: and subsequently verifies if it contains specific substrings corresponding to known malicious MIME types.
The primary failure point is the implementation of an incomplete blocklist. The code explicitly searches for text/html, image/svg+xml, and application/xhtml+xml. By design, this approach implicitly allows any MIME type not explicitly defined in the blocklist. Attackers leverage this design flaw by supplying text/xml or application/xml, which the sanitizer evaluates as benign and passes through unmodified.
Furthermore, the vulnerable /api/icon/getDynamicIcon endpoint processes the content parameter when the type parameter is set to 8. The application embeds this user-controlled content directly into an SVG string template using the fmt.Sprintf function. The software performs this operation without secondary escaping or structural validation, meaning the bypassed payload is injected directly into the active Document Object Model (DOM) when the endpoint returns the image/svg+xml response.
To understand the vulnerability mechanism, we must examine the specific implementation of the SanitizeSVG function in SiYuan version 3.6.0. The code iterates over attributes and attempts to sanitize href values based on their content. The logic applies a targeted blocklist against data: URIs.
// Vulnerable implementation in v3.6.0
if strings.HasPrefix(val, "data:") {
if strings.Contains(val, "text/html") || strings.Contains(val, "image/svg+xml") || strings.Contains(val, "application/xhtml+xml") {
continue // Strips the attribute
}
// Implicitly allows data:text/xml
}In this vulnerable state, if the val variable contains data:text/xml, the condition evaluates to false. The function does not execute the continue statement, and the malicious href attribute remains in the parsed SVG structure. The system subsequently renders this structure to the client.
To effectively remediate this vulnerability, the sanitization logic must shift from a blocklist model to a strict allowlist model. An allowlist explicitly defines the permissible data types and denies all others by default. The following proposed code change demonstrates this secure implementation strategy.
// Recommended allowlist implementation
if strings.HasPrefix(val, "data:") {
safe := strings.HasPrefix(val, "data:image/png") ||
strings.HasPrefix(val, "data:image/jpeg") ||
strings.HasPrefix(val, "data:image/gif") ||
strings.HasPrefix(val, "data:image/webp")
if !safe {
continue // Strips anything not explicitly allowed
}
}Exploiting GHSA-4MX9-3C2H-HWHG requires an attacker to construct a specific HTTP GET request targeting the unauthenticated dynamic icon endpoint. The attacker must supply the type=8 parameter to force the application to process the content parameter. The content parameter contains the malicious SVG structure designed to bypass the sanitizer.
The attacker crafts an <a> element containing an href attribute with a data:text/xml URI. This URI encapsulates a secondary SVG element containing an onload event handler. When the victim interacts with the generated link, the browser processes the data:text/xml content, identifies the nested SVG, and immediately fires the onload event, executing the attacker's JavaScript.
# Proof of Concept: data:text/xml bypass
curl -s --get "http://127.0.0.1:6806/api/icon/getDynamicIcon" \
--data-urlencode 'type=8' \
--data-urlencode 'content=</text><a href="data:text/xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 onload=%27alert(document.domain)%27/%3E">click</a><text>' \
| grep -o '<a [^>]*>'The server returns an image/svg+xml response containing the unmodified malicious link. Because the response is explicitly typed as an SVG image, the victim's browser renders it natively. The execution context of the injected script is the domain hosting the SiYuan application, granting the script full access to application resources and session data.
The impact of this vulnerability is critical due to the unauthenticated nature of the target endpoint and the high privileges associated with the application's execution context. An attacker requires zero prior access or credentials to deliver the payload. The vulnerability relies solely on the victim accessing a crafted URL, which can be distributed via email, forums, or integrated into external websites.
Upon successful execution, the attacker achieves arbitrary JavaScript execution within the SiYuan application's origin. This access allows the script to silently harvest session tokens, authentication cookies, and API keys. The script can then transmit this sensitive data to an external server controlled by the attacker, leading to complete session hijacking.
Beyond credential theft, the malicious script can interact with the SiYuan API on behalf of the authenticated user. The attacker can extract sensitive notes, modify document contents, or alter application configurations. This capability represents a total compromise of the integrity and confidentiality of the user's personal knowledge base.
In deployments where SiYuan operates as a desktop application built on Electron, the impact can escalate from Cross-Site Scripting to Remote Code Execution (RCE). If the Electron environment misconfigures web preferences, such as enabling nodeIntegration or disabling contextIsolation, the injected JavaScript can access the underlying Node.js runtime. This access permits the execution of arbitrary system commands on the host operating system.
To effectively mitigate this vulnerability, developers must abandon the blocklist approach in the SanitizeSVG function. The remediation requires implementing an allowlist that strictly defines permissible image types for data: URIs. The application should only permit known-safe image formats, such as data:image/png, data:image/jpeg, and data:image/webp, while stripping any URI that deviates from this defined list.
System administrators can deploy Web Application Firewall (WAF) rules to detect and block exploitation attempts at the network perimeter. The WAF should inspect HTTP GET requests targeting the /api/icon/getDynamicIcon endpoint. Specifically, the rule must trigger when the content parameter contains strings matching data:text/xml or data:application/xml.
Security teams should perform retrospective log analysis to identify potential prior exploitation. The analysis should focus on the application access logs, searching for the /api/icon/getDynamicIcon endpoint where the content query parameter contains anomalous data: URIs or encoded SVG syntax. Identifying these patterns can indicate whether attackers have actively leveraged this bypass in the environment.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
SiYuan B3log | >= 3.5.9, <= 3.6.0 | - |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 9.3 |
| Impact | High (Confidentiality & Integrity) |
| Exploit Status | PoC Available |
| Authentication | None Required |