Authentication mechanism absence or evasion In flask-security-too

Description

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

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...

Mitigation

Update Impact

Minimal update. May introduce new vulnerabilities or breaking changes.

Ecosystem
Package
Affected version
Patched versions