Skip to main content

Flask-Security-Too CVE-2026-46715

MEDIUM
Improper Authentication (CWE-287)
2026-05-22 https://github.com/pallets-eco/flask-security GHSA-97r5-pg8x-p63p
Share

Severity by source

SUSE PRIMARY
6.8 MEDIUM
AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N

Primary rating from SUSE · only source for this CVE.

Lifecycle Timeline

2
Source Code Evidence Fetched
May 23, 2026 - 00:31 vuln.today
Analysis Generated
May 23, 2026 - 00:31 vuln.today

DescriptionCVE.org

Summary

Flask-Security-Too 5.8.0's OAuth reauthentication flow can mark a session as fresh after verifying an OAuth account that belongs to a different user.

If an attacker can operate an already-authenticated but stale victim session, they can complete OAuth verification using their own OAuth identity. The victim session is then treated as recently reauthenticated, allowing freshness-protected account actions to proceed. This was reproduced against the built-in /change-username route.

Details

The issue is in the OAuth verification callback.

_oauth_response_common() resolves the OAuth provider identity to a Flask-Security user:

  • flask_security/oauth_glue.py:101-108

oauth_verify_response() then accepts any resolved user and updates the current session freshness timestamp:

  • flask_security/oauth_glue.py:182-214
  • flask_security/oauth_glue.py:201-204

The missing check is that the OAuth-resolved user must match the current authenticated session user. In the failing case:

  • current session user: victim@example.com
  • OAuth verified user: attacker@example.com
  • session marked fresh: yes

So the attacker is not logging in as the victim, but they are satisfying the victim session's reauthentication requirement with a different account.

PoC

Tested version:

  • Flask-Security-Too 5.8.0
  • tag 5.8.0
  • commit 08288dff6907e413d848a16aaf43fc2c2b2a3b72

Used a minimal Flask app with:

python
  SECURITY_OAUTH_ENABLE = True
  SECURITY_OAUTH_BUILTIN_PROVIDERS = ["github"]
  SECURITY_FRESHNESS = timedelta(seconds=1)
  SECURITY_FRESHNESS_GRACE_PERIOD = timedelta(seconds=0)
  SECURITY_USERNAME_ENABLE = True
  SECURITY_CHANGE_USERNAME = True

  The OAuth provider was replaced with a localhost mock provider
  returning attacker@example.com. This avoids hitting a live third-party
  provider while still exercising Flask-Security-Too's real OAuth
  verification handler.

  Reproduction steps:

  1. Log in as victim@example.com.
  2. Wait until the session is no longer fresh.
  3. Confirm POST /change-username is blocked with 401 and
     reauth_required=true.
  4. Start OAuth verification with POST /login/oauth-verify-start/
     github.
  5. Complete the callback with an OAuth identity for
     attacker@example.com.
  6. Confirm the session is still for victim@example.com, but fs_paa has
     been updated.
  7. Retry POST /change-username.
  8. The victim user's username is changed successfully.

  Observed result:

  {
    "pre_bypass_status": 401,
    "pre_bypass_reauth_required": true,
    "attacker_identity": "attacker@example.com",
    "oauth_verify_response_status": 302,
    "post_bypass_change_username_status": 200,
    "final_email": "victim@example.com",
    "final_username": "victimowned1777878574",
    "direct_impact_verified": true
  }

  Note: CSRF was disabled in the local harness only to keep the test
  focused on the reauthentication check. This is not a CSRF bypass
  report.

  This bypasses Flask-Security-Too's freshness/reauthentication
  boundary.

  Applications using OAuth verification together with freshness-
  protected account operations may allow a stale victim session to be
  refreshed using a different user's OAuth account. In my test, this
  allowed the victim account's username to be changed through Flask-
  Security-Too's built-in /change-username route.

  A likely fix is to reject OAuth verification unless the resolved OAuth
  user matches current_user before updating session["fs_paa"].

AnalysisAI

Session freshness bypass in Flask-Security-Too 5.8.0 allows an attacker who controls a stale authenticated victim session to satisfy the victim session's reauthentication requirement using their own OAuth identity, not the victim's. The flaw in oauth_glue.py causes oauth_verify_response() to update session["fs_paa"] (the freshness timestamp) without verifying that the OAuth-resolved user matches the currently authenticated session user. Exploitation was confirmed via a detailed proof-of-concept that successfully changed a victim user's username through the built-in /change-username route after bypassing the freshness gate. Publicly available exploit code exists; no CISA KEV listing at time of analysis.

Technical ContextAI

Flask-Security-Too is a Flask extension providing full-stack security primitives for Python web applications, including OAuth-based reauthentication flows. The affected package is pip/flask-security-too (CPE: pkg:pip/flask-security-too). The root cause maps to CWE-287 (Improper Authentication): specifically, the OAuth verification callback in flask_security/oauth_glue.py at lines 182-214 resolves an OAuth provider identity to a Flask-Security user object via _oauth_response_common() (lines 101-108), but the subsequent oauth_verify_response() function accepts any successfully resolved user and writes the current timestamp into session["fs_paa"] - the Flask-Security freshness indicator - without asserting that the resolved OAuth user matches current_user. This decoupling between identity resolution and session ownership is the precise root cause. Applications configure freshness enforcement via SECURITY_FRESHNESS and SECURITY_FRESHNESS_GRACE_PERIOD settings; routes guarded by freshness checks (e.g., /change-username) perform a 401 with reauth_required=true when the session is stale, and they rely on this OAuth verification pathway to re-establish freshness.

RemediationAI

Upgrade Flask-Security-Too to version 5.8.1, which is confirmed as the fixed release per the GHSA advisory at https://github.com/pallets-eco/flask-security/security/advisories/GHSA-97r5-pg8x-p63p. Install via pip install flask-security-too>=5.8.1. If immediate upgrade is not possible, the most targeted compensating control is to disable OAuth-based reauthentication by setting SECURITY_OAUTH_ENABLE = False or removing OAuth builtin providers - this eliminates the vulnerable code path entirely but removes OAuth login functionality as a trade-off. Alternatively, removing freshness-protected routes (e.g., disabling SECURITY_CHANGE_USERNAME) narrows the exploitable attack surface but does not eliminate the underlying flaw. Requiring users to reauthenticate via password rather than OAuth for sensitive operations (if configurable) would also mitigate the specific bypass. Do not rely on CSRF controls alone as a compensating control; the PoC explicitly notes CSRF was disabled to isolate the reauthentication flaw, meaning CSRF protection is orthogonal to this issue.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2026-55255 HIGH POC
8.4 Jun 19

Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing

Vendor StatusVendor

SUSE

Severity: Moderate
Product Status
SUSE Linux Enterprise Desktop 15 SP7 Not-Affected
SUSE Linux Enterprise High Performance Computing 15 SP7 Not-Affected
SUSE Linux Enterprise Module for Basesystem 15 SP7 Not-Affected
SUSE Linux Enterprise Module for Python 3 15 SP7 Not-Affected
SUSE Linux Enterprise Server 15 SP7 Not-Affected

Share

CVE-2026-46715 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy