Skip to content

Session-cookie authentication branch of `CheckAuth()` has no Origin/Referer validation and the session cookie sets no explicit `SameSite` attribute, leaving CSRF protection entirely dependent on undocumented browser defaults

Moderate
88250 published GHSA-hhm2-g993-p656 Aug 3, 2026

Package

gomod github.com/siyuan-note/siyuan/kernel (Go)

Affected versions

3.7.3

Patched versions

v3.7.4

Description

Package

gomod github.com/siyuan-note/siyuan/kernel (Go)

Affected versions

<= 3.7.3 (confirmed present in 3.7.3 by source review)

Patched versions

(none yet — leave blank until a fix is released)

Description

Summary

This is a different bug class from the three throttle issues already reported (GHSA-w3xh-mmmh-r54v, GHSA-m6w6-p7pc-fpg2, and the Publish Service one submitted separately): a missing/inconsistent CSRF defense. CheckAuth() implements Origin-header validation for one specific unauthenticated fallback case, explicitly because the maintainers previously recognized "a malicious website reaching the local kernel from a browser tab" as a real threat (referencing issue #9180 in the code). But the authenticated session-cookie branch of the same function , reached whenever a lock-screen AccessAuthCode is configured and the user is logged in , has no equivalent Origin/Referer check at all, and the session cookie itself is issued with no explicit SameSite attribute. The only thing currently standing between this and classic cross-site request forgery is each browser's undocumented, non-guaranteed default SameSite policy, not anything the application enforces itself.

Details

1. The precedent that Origin validation matters here, but only applied to one branch:

// kernel/model/session.go, CheckAuth()
if "" == Conf.AccessAuthCode {
    if util.SiYuanAccessAuthCodeBypass {
        c.Set(RoleContextKey, RoleAdministrator)
        c.Next()
        return
    }

    // Authenticate requests with the Origin header other than 127.0.0.1 https://github.com/siyuan-note/siyuan/issues/9180
    clientIP := c.ClientIP()
    host := c.GetHeader("Host")
    origin := c.GetHeader("Origin")
    forwardedHost := c.GetHeader("X-Forwarded-Host")
    if !localhost ||
        ("" != clientIP && !util.IsLocalHostname(clientIP)) ||
        ("" != host && !util.IsLocalHost(host)) ||
        ("" != origin && !util.IsLocalOrigin(origin)) ||
        ("" != forwardedHost && !util.IsLocalHost(forwardedHost)) {
        c.JSON(http.StatusUnauthorized, map[string]any{"code": -1, "msg": "Auth failed: for security reasons, please set [Lock screen password] when using non-127.0.0.1 access\n\n为安全起见,使用非 127.0.0.1 访问时请设置 [锁屏密码]"})
        c.Abort()
        return
    }

    c.Set(RoleContextKey, RoleAdministrator)
    c.Next()
    return
}

The code comment cites issue #9180 verbatim , the maintainers' own stated reason for this check is to stop a malicious page loaded in a normal browser tab from reaching the locally-running kernel. That's a textbook CSRF/DNS-rebinding threat model, and they treated it as worth an explicit, dedicated check.

2. But once AccessAuthCode is set (i.e. once the exact protection this issue exists for is actually turned on), the check that grants access is purely cookie-based, with none of the above validation:

// 通过 Cookie
session := util.GetSession(c)
workspaceSession := util.GetWorkspaceSession(session)
if workspaceSession.AccessAuthCode == Conf.AccessAuthCode {
    c.Set(RoleContextKey, RoleAdministrator)
    c.Next()
    return
}

No Origin, Host, or X-Forwarded-Host check anywhere in this branch or afterward for the general session-cookie case. If a valid session cookie is attached to the request, it succeeds , full stop , regardless of what page originated the request.

3. And the cookie itself sets no explicit SameSite, so there is no server-enforced backstop:

// kernel/server/serve.go, Serve()
sessionStore = cookie.NewStore([]byte(cookieKey))
sessionStore.Options(sessions.Options{
    Path:     "/",
    Secure:   util.SSL,
    HttpOnly: true,
    // no SameSite set
})

gorilla/sessions' Options.SameSite defaults to http.SameSiteDefaultMode (0) when unset, which omits the SameSite attribute from the Set-Cookie header entirely. The only reason this isn't trivially exploitable today is that current major browsers (Chrome ≥80, Firefox, Edge) unilaterally treat a cookie with no SameSite attribute as Lax. That is a browser-side mitigation the application does not control, does not document reliance on, and cannot guarantee for every client (older browsers, some embedded WebView components, or any future change to that default policy).

Recommended fix

  • Set SameSite: http.SameSiteStrictMode (or at minimum Lax) explicitly in the sessions.Options cookie store config, rather than relying on browser defaults.
  • Apply the same Origin/Host/X-Forwarded-Host validation already implemented for the empty-AccessAuthCode branch to the session-cookie branch as well, so the check isn't conditional on whether a lock-screen password happens to be set.
  • Consider a conventional CSRF token (double-submit cookie or synchronizer token) for state-changing endpoints as defense-in-depth beyond SameSite, consistent with how seriously the rest of this codebase treats auth hardening.

Affected products

Field Value
Ecosystem Go
Package name github.com/siyuan-note/siyuan/kernel
Affected versions <= 3.7.3
Patched versions (none yet)

Severity

Field Value
Vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N (reflects that a non-default/legacy client is currently required for practical exploitation)
Score Low–Moderate. I'm intentionally not scoring this as high as the throttle bugs , real-world exploitability today is blocked by mainstream browsers' default SameSite=Lax behavior. I'd rather flag this honestly as a hardening gap than dress it up as a confirmed Critical, since I can't demonstrate a working bypass of that default in this environment.

Weaknesses (CWE)

  • CWE-352 — Cross-Site Request Forgery
  • CWE-1275 — Sensitive Cookie Without 'SameSite' Attribute

Relationship to previously reported/submitted issues

Not related to GHSA-w3xh-mmmh-r54v, GHSA-m6w6-p7pc-fpg2, or the Publish Service throttle finding — those are all CWE-307 (missing rate limiting on a credential check). This is a structurally different weakness (missing CSRF defense-in-depth) in a different part of the same CheckAuth() function, and is not fixed by anything those three would need to fix.

Credits

  • alhamrizvi-cloud — Reporter

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
Required
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:L/A:N

CVE ID

No known CVE

Weaknesses

Cross-Site Request Forgery (CSRF)

The web application does not, or cannot, sufficiently verify whether a request was intentionally provided by the user who sent the request, which could have originated from an unauthorized actor. Learn more on MITRE.

Sensitive Cookie with Improper SameSite Attribute

The SameSite attribute for sensitive cookies is not set, or an insecure value is used. Learn more on MITRE.

Credits