Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

CVE-2026-46715 — flask-security-too

Fix: pallets-eco/flask-security@8e69f3a

CVE-2026-46715 is a Improper Authentication vulnerability in flask-security-too. A fix is available for flask-security-too — see the affected versions and patch details below.

Flask-Security-Too OAuth reauthentication freshness bypass via cross- user OAuth identity acceptance

Also known asGHSA-97r5-pg8x-p63pPYSEC-2026-2478
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 3, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-46715.

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs40th percentile — riskier than 40% of all scored CVEsHighest risk
0.00%0.33%0.66%0.99%0.3%0.5%0.5%Aug 26Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
🐍flask-security-too

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.

Description

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:

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:

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 [email protected]. 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 [email protected].
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
   [email protected].
6. Confirm the session is still for [email protected], 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": "[email protected]",
  "oauth_verify_response_status": 302,
  "post_bypass_change_username_status": 200,
  "final_email": "[email protected]",
  "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"].

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIflask-security-too≥ 5.8.0&&< 5.8.15.8.1pip install --upgrade 'flask-security-too==5.8.1'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for flask-security-too, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update flask-security-too to 5.8.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-46715 is resolved across your whole dependency graph.

  3. Workarounds

    Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.

Frequently Asked Questions

### 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_respo
O3 Security · Impact-Aware SCA

Is CVE-2026-46715 in your dependencies?

Find it across PyPI, including transitive dependencies.

CVE-2026-46715: CSRF — Fixed in 5.8.1 | O3 Security