GHSA-f66q-9rf6-8795: Flask-Security-Too: WebAuthn reauthentication freshness bypass via cross-user assertion
Summary
Flask-Security-Too 5.8.0 and 5.8.1 mark a session as reauthentication-fresh after processing a WebAuthn assertion whose proven credential belongs to a different user than the currently authenticated session user. The check that GHSA-97r5-pg8x-p63p added on the OAuth reauthentication path (user.email == current_user.email) is missing on the WebAuthn reauthentication path. An attacker who owns any WebAuthn credential registered to any account on the deployment can satisfy a victim session's freshness gate by submitting their own WebAuthn proof into the victim session.
Affected versions
Flask-Security-Too >= 5.8.0, <= 5.8.1 (current main commit 5c44c76e33a20b67d02115e26d2da4bab18c094e).
GHSA-97r5-pg8x-p63p (published 2026-05-22) shipped its fix in 5.8.1 only on oauth_glue.py; webauthn.py was not touched and remains exploitable in 5.8.1.
Privilege required
Authenticated attacker on the same Flask-Security deployment, owning at least one WebAuthn credential of any usage (first / secondary / verify) that is registered to their own account. The attacker also needs the ability to drive HTTP requests against the WebAuthn endpoints inside the victim session (e.g. a separate gadget such as CSRF + cookie-based auth, an XSS that doesn't reach the cookie itself but can move the session through endpoints, or an existing session-fixation gadget; or the rarer but easier case of an attacker who has direct access to the victim's not-yet-fresh session via a shared browser). The point of the freshness gate is to defend exactly that "I have the session but it isn't fresh enough to do sensitive things" position, so any context in which freshness would have protected the victim is also the context in which this bypass matters.
Vulnerable code
flask_security/webauthn.py:846-889 (commit
5c44c76e33a20b67d02115e26d2da4bab18c094e):
@auth_required(lambda: cv("API_ENABLED_METHODS"))
def webauthn_verify_response(token: str) -> ResponseValue:
form = t.cast(
WebAuthnSigninResponseFor
Details
Original advisory: https://github.com/advisories/GHSA-f66q-9rf6-8795
More from GitHub Security Advisories
- criticalGHSA-g936-7jqj-mwv8: TSDProxy: Internal proxy auth token forwarded to backend services enables management API …2026-07-10
- highGHSA-fpg8-7664-jc5q: melange: Incomplete package integrity verification allows data section substitution2026-07-10
- mediumGHSA-48rx-c7pg-q66r: Excon does not redact additional sensitive/risky headers when following redirects2026-07-10
- highGHSA-h4g2-xfmw-q2c9: Clauster: Non-loopback deployments can serve the dashboard unauthenticated when auth.enab…2026-07-10
- mediumGHSA-rqq5-2gf9-4w4q: Secure Headers: CSP directive injection via sandbox, plugin_types, and report_to when giv…2026-07-10