GHSA-97r5-pg8x-p63p

Suggest an improvement
Source
https://github.com/advisories/GHSA-97r5-pg8x-p63p
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-97r5-pg8x-p63p/GHSA-97r5-pg8x-p63p.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-97r5-pg8x-p63p
Aliases
  • CVE-2026-46715
Published
2026-05-22T17:48:54Z
Modified
2026-05-22T18:00:09.718714785Z
Summary
Flask-Security-Too OAuth reauthentication freshness bypass via cross- user OAuth identity acceptance
Details

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 SECURITYOAUTHENABLE = True SECURITYOAUTHBUILTINPROVIDERS = ["github"] SECURITYFRESHNESS = timedelta(seconds=1) SECURITYFRESHNESSGRACEPERIOD = timedelta(seconds=0) SECURITYUSERNAMEENABLE = True SECURITYCHANGE_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:

    { "prebypassstatus": 401, "prebypassreauthrequired": true, "attackeridentity": "attacker@example.com", "oauthverifyresponsestatus": 302, "postbypasschangeusernamestatus": 200, "finalemail": "victim@example.com", "finalusername": "victimowned1777878574", "directimpact_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 currentuser before updating session["fspaa"].

Database specific
{
    "github_reviewed_at": "2026-05-22T17:48:54Z",
    "github_reviewed": true,
    "cwe_ids": [
        "CWE-287"
    ],
    "nvd_published_at": null,
    "severity": "MODERATE"
}
References

Affected packages

PyPI / flask-security-too

Package

Name
flask-security-too
View open source insights on deps.dev
Purl
pkg:pypi/flask-security-too

Affected ranges

Type
ECOSYSTEM
Events
Introduced
5.8.0
Fixed
5.8.1

Affected versions

5.*
5.8.0

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-97r5-pg8x-p63p/GHSA-97r5-pg8x-p63p.json"