← Open-source disclosures

Advisory · BookStack

Forced logout via CSRF on the SAML2 logout route

Project
BookStack
Affected
v26.09.1 and earlier
Fixed in
v26.09.2
Severity
Low (Xora rating)
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L
Weakness
CWE-352
Reported
Oct 9, 2026
Fixed
Oct 20, 2026

Summary

BookStack applies CSRF protection across the application, with one exception: the saml2/* route group. Because of that exemption, POST /saml2/logout accepted a request with no CSRF token. The session cookie is SameSite=Lax, so a page on a host that shares BookStack’s registrable domain could log a signed-in user out.

The impact is a forced logout and nothing more. An ordinary cross-site page cannot trigger it, and it gives an attacker no access to the account or its data.

Root cause

// app/Http/Middleware/VerifyCsrfToken.php (v26.09.1)
protected $except = [
    'saml2/*',
];

BookStack added application-wide CSRF verification in release 21.11 (CVE-2021-3944). saml2/* was the only route group carved out of it, so the user-initiated logout route accepted a tokenless POST. The session cookie is set with same_site => 'lax' (app/Config/session.php). Lax is scoped to the registrable domain: the browser withholds the cookie on a genuinely cross-site POST but sends it on one from a sibling subdomain.

Preconditions

The first precondition is what keeps this rated Low, and it is what the AC:H in the CVSS vector records.

Reproduction

With BookStack at docs.example.com, serve this page from other.example.com and open it as a signed-in user:

<form action="https://docs.example.com/saml2/logout" method="POST"></form>
<script>document.forms[0].submit()</script>

In a real browser, the request from the same-site host ended the session. The identical request from a cross-site host did not, because the browser withheld the cookie. That contrast is the evidence.

The fix

We suggested narrowing the exemption to the identity-provider callbacks that cannot carry a CSRF token, or checking Origin and Referer on the exempt routes. BookStack went further: in v26.09.2 the exemption list is empty, so no route skips CSRF verification. We confirmed that change in the source at the v26.09.2 tag. We have not retested the fixed release in a browser.

What we do not claim

What the engine got wrong

The Xora engine found the missing CSRF check, but its first record said any website could log a user out. That was wrong. The session cookie is SameSite=Lax, so the browser does not send it with a cross-site POST. In a real browser the cross-site attack failed and only the same-site variant worked, so we reported the narrower claim and rated it Low.

The engine was right that the protection was missing and wrong about who could reach it, and reachability is what sets the severity. We recorded this as a check for the engine to learn: when a finding depends on the browser sending a session cookie, read the cookie’s SameSite setting from the source, then ask whether the attacker’s page is cross-site or only on a sibling subdomain.

Timeline

Found by the Xora engine, confirmed by a person, and reported under our coordinated disclosure policy. Questions or corrections: security@getxora.ai.