Sep 4, 2026·7 min read·30 visits
A session-pollution flaw in SiYuan's WebSocket implementation allows anonymous network users to passively intercept all real-time workspace edits, bypassing publication boundaries.
CVE-2026-72810 is a critical publish-boundary bypass vulnerability in the SiYuan personal knowledge management system before version 3.7.4. The flaw lies in the backend real-time WebSocket broadcast mechanism. When configured in public publish mode, the system fails to differentiate between unauthenticated public reader sessions and authorized administrative sessions within its global connection pool. This architectural oversight allows unauthenticated remote attackers connecting to the public WebSocket endpoint on port 6808 to passively receive real-time, raw workspace modification events, including keystroke logs, block updates, and content from protected or forbidden documents.
SiYuan is a local-first personal knowledge management platform designed to allow users to organize, edit, and publish their personal workspaces. To facilitate public sharing, the application includes a publish mode, which exposes select notes to anonymous web readers typically via port 6808. In this configuration, the publish surface acts as a read-only presentation layer meant to be strictly isolated from the underlying administrative workspace interface.
The core of the security boundary relies on the assumption that anonymous readers can only access public-facing pages and cannot view live, administrative workspace state. However, the system utilizes a real-time communication framework to push structural and content updates dynamically. This real-time synchronization layer exposes an architectural attack surface because both public and administrative users establish persistent WebSocket connections to the same underlying kernel process.
CVE-2026-72810 represents a failure to maintain this security boundary. Because the application does not separate public reader sessions from administrative sessions in its global WebSocket pool, unauthenticated network clients can register their sockets and receive unfiltered broadcast messages. This leads to a complete compromise of confidentiality, allowing unauthorized observers to read private notes as they are being typed.
The technical root cause of CVE-2026-72810 involves two primary software-level flaws: WebSocket broadcast session pollution and weak JSON Web Token (JWT) audience validation. The first flaw resides in the WebSocket session manager within the file kernel/util/websocket.go. The SiYuan kernel uses the third-party melody WebSocket library to manage concurrent connections, storing all active client connections in a global sync.Map named sessions without tracking their respective authorization contexts.
When a user performs any action in the editor—such as typing, adding structural block components, or modifying document metadata—the kernel generates synchronization events. The broadcast functions, including Broadcast, broadcastOthers, and SessionsByType, iterate over this global connection map and write the raw JSON event payload directly to every active connection. Because the system did not perform authorization checks to filter out public readers from this loop, any unauthenticated client connected to the WebSocket endpoint on port 6808 was treated as a valid recipient of administrative updates.
The second contributing factor is a privilege confusion vulnerability inside the token validation logic in kernel/model/auth.go. The verification helper IsPublishServiceToken was designed to authenticate incoming requests from the publish service. However, the logic only verified that the token's issuer claim (iss) matched the string siyuan-kernel. Because general application sessions and administrative users also utilized tokens signed by the same issuer, the lack of audience validation allowed lower-privileged clients to reuse tokens or bypass validation entirely, weakening the overall trust boundary.
To visualize the flow of events and the root cause of this data leak, refer to the following architectural diagram showing the unsanitized broadcast path:
An analysis of the patch implemented in commit ba948639d7f6bd5594ce584072dc68310da87a68 reveals how the developers solved both the session pollution and JWT validation flaws. In the vulnerable version, the broadcast loop in kernel/util/websocket.go wrote data directly to all sessions stored in the map without validation. The fix introduces a helper function, isPublishSession, which queries the session's metadata attributes:
func isPublishSession(session *melody.Session) bool {
isPublish, ok := session.Get(\"isPublish\")
return ok && isPublish == true
}This metadata check has been integrated into every broadcast path in kernel/util/websocket.go. For instance, in the global broadcast loop, the iterator now explicitly checks if the session is registered as a publish session. If the condition is met, the iteration returns true, skipping the write operation and preventing the leak of real-time administrative payloads to unauthenticated connections:
appSessions.Range(func(key, value any) bool {
session := value.(*melody.Session)
if isPublishSession(session) {
return true // Skip broadcasting data to this read-only public session
}
session.Write(msg)
return true
})Additionally, the JWT validation mechanism in kernel/model/auth.go was strengthened. The updated validation logic now strictly verifies both the issuer and the audience (aud) claim against the hardcoded constant siyuan-publish-server. This ensures that tokens intended for the public publish service cannot be misused to access or authenticate administrative components, enforcing strict cryptographic separation between security domains:
const publishServiceAudience = \"siyuan-publish-server\"
func IsPublishServiceToken(token *jwt.Token) bool {
...
tokenIssuer, ok := claims[\"iss\"].(string)
if !ok || tokenIssuer != iss {
return false
}
audience, err := claims.GetAudience()
return err == nil && slices.Contains(audience, publishServiceAudience)
}Exploitation of CVE-2026-72810 does not require complex cryptographic attacks or active memory manipulation. The vulnerability is exploited passively because the system automatically pushes data to any registered WebSocket client. The threat actor first conducts reconnaissance to locate an exposed SiYuan instance with public publishing enabled. By default, the publication port is 6808, but the interface may also be exposed behind an HTTP reverse proxy forwarding the /ws path.
Once the target is identified, the attacker initializes a standard WebSocket handshake targeting the /ws path of the publish surface. No authentication tokens or administrative cookies are required to complete this handshake. Upon successful connection establishment, the attacker's client is added to the application's global session map, where it remains active in a passive listening state.
As the owner of the workspace interacts with their notes, the SiYuan kernel writes every edit event to the global session map. These JSON-formatted frames contain raw text additions, structural block modifications, and keystroke logs. The attacker's WebSocket client automatically receives these payloads, allowing the threat actor to reconstruct sensitive documents in real time, even if those documents are password-protected or configured as private.
The security impact of CVE-2026-72810 is highly severe, leading to a complete compromise of confidentiality for active workspaces. Because personal knowledge management systems are frequently used to store highly sensitive information—such as credentials, intellectual property, personal diaries, and proprietary business documentation—passive interception of these editing streams can result in critical data exposure.
This vulnerability is assigned a CVSS v3.1 base score of 8.6, reflecting network-based accessibility, low complexity, and zero privilege requirements. The scope metric is marked as 'Changed' (C) because the compromise of the WebSocket session management layer allows access to data managed by a separate security domain (the private administrative workspace). This highlights the architectural severity of mixing public and administrative sessions within the same communication channel.
From a threat perspective, although there is currently no active public weaponized exploit, the ease of exploitation makes it a prime target for opportunistic attackers. Passive data exfiltration is difficult to detect using standard endpoint protection, as the malicious client simply utilizes legitimate API pathways to receive the stream. This underscores the need for robust authorization validation at the system boundary before connections are registered.
The primary and most effective remediation path is to upgrade all SiYuan installations to version 3.7.4 or later. This version contains the complete session isolation patch and the hardened JWT validation checks, eliminating the data broadcast leak. Administrators should review their deployment versions and ensure that any containerized or self-hosted instances are configured to pull the latest stable release.
If upgrading immediately is not feasible, administrators must apply network-level mitigations to restrict exposure. Access to port 6808 should be limited to trusted IP addresses using firewall rules or security groups. Alternatively, if a reverse proxy is deployed in front of SiYuan, administrators can configure rule sets to block or restrict incoming WebSocket upgrade requests targeting the /ws endpoint on public-facing domains, limiting access to local loopback addresses.
Furthermore, developers building custom plugins or integrations for SiYuan must ensure they do not bypass the updated WebSocket utility functions. Direct writes using raw melody.Session.Write operations bypass the newly implemented isPublishSession check entirely. Security teams should audit custom code paths to verify that all WebSocket broadcasts route strictly through the sanitized kernel/util/websocket.go functions.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
SiYuan siyuan-note | < 3.7.4 | 3.7.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-862 (Missing Authorization) |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 8.6 (High) |
| CVSS v4.0 Score | 9.2 (Critical) |
| EPSS Score | 0.00313 (0.313%) |
| Exploit Status | none |
| CISA KEV Status | Not Listed |
The software does not perform an authorization check when an actor attempts to access a resource or perform an action.
CVE-2026-109619 (PHP2Shell) is a critical Use-After-Free vulnerability in the core PHP engine caused by improper global state cleanup during out-of-memory exception handling across persistent worker requests.
In Python virtualenv prior to version 21.14.9, activation script generators and configuration writers use Path.exists() before writing files. Because Path.exists() resolves symbolic links, it returns False for dangling symlinks. Consequently, virtualenv skips unlinking pre-planted symbolic links or hard links, writing data directly to target locations outside the intended virtual environment directory.
A remote code execution vulnerability exists in Microsoft .NET due to untrusted data deserialization within the PresentationCore component. The flaw stems from implicit auto-conversion flags during clipboard data retrieval operations.
An out-of-bounds write vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio allows unauthenticated remote attackers to execute arbitrary code via crafted pixel-shader bytecode or auto-converted clipboard payloads.
ASP.NET Core contains a thread deadlock vulnerability (CWE-833) that allows an unauthenticated remote attacker to cause a denial of service over the network by exhausting server thread pool resources.
CVE-2026-70035 is a high-severity Remote Code Execution (RCE) vulnerability in Microsoft .NET Framework, .NET runtime, and Visual Studio caused by improper handling during the deserialization of untrusted data (CWE-502). An unauthenticated attacker can execute arbitrary code within the context of the affected process by delivering a crafted serialized payload.