Hall of Fame
Back to Hall of Fame Contents Back to WeKan Website

CasTokenBleed

CVEIconVulnerability nameDate Responsible Security Disclosure byStarsProcessVulnerabilities
-

CasTokenBleed 2026-10-02 xet7 Gold starGold starGold star Found while auditing the CAS login callback after the 2026-10-02 Hall of Fame review; fixed by xet7.

The CAS callback stored the identity CAS had validated under whatever casToken the callback URL carried, and that token is chosen by the browser. An attacker picked a token, sent a victim who was already signed in to CAS a link to the CAS login whose service URL carried that token, CAS sent the victim back with a ticket, WeKan stored the victim's identity under the attacker's token, and the attacker logged in with it as the victim.

The browser that starts a CAS login now sets a cookie with its token, and the callback is accepted only when that cookie matches. A ticket parameter on an instance without CAS is left to its route.

CWE-352: login cross-site request forgery leading to account takeover. Critical severity where CAS is enabled. No CVE assigned. Fix prepared locally for the Upcoming release; not yet released.

Details

A CAS login starts in the browser, which makes up a casToken and sends the user to the CAS server with a service URL that carries it. CAS sends the user back with a ticket; WeKan validates the ticket and stores the identity CAS returned under that token, and the browser then logs in with cas: { credentialToken }.

Nothing tied the token to the browser that made it up. An attacker could choose a token, send a victim who was already signed in to CAS a link to the CAS login page whose service parameter is WeKan's own address with ?casToken=KNOWN added, and wait. CAS sent the victim straight back with a ticket for their own account, WeKan stored the victim's identity under KNOWN, and the attacker logged in with cas: { credentialToken: 'KNOWN' } as the victim.

This is a different fault from CasRaceBleed, the concurrent-login race reported by meifukun, which mixed up two genuine logins; here the attacker starts no login of their own at the CAS server.

Fix

The browser that starts a CAS login sets a SameSite=Lax cookie holding its token, and the callback stores an identity only when the token in the URL matches that cookie, which a link sent to somebody else cannot carry. A ticket parameter on an instance without CAS is left to the route it was meant for.

Detection

A callback whose token the browser did not set is refused and summarized as CasTokenBleed in Admin Panel → Problems (catalog key authn.cas-state, recorded through the cas.state-mismatch canary).

Verification

Unit tests in tests/casStateBinding.test.cjs check that the state is read only from its own cookie, reproduce the reported attack - a callback whose token this browser did not set is refused and recorded - and the negative test fails unless the browser that starts a login sets the state it will be checked against. The unit tests pass in the WeKan repository. A login against a real CAS server was not tested.

Source fix and regression tests