
PEACH
Un cadre d’isolation des locataires
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.
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-108oauth_verify_response() then accepts any resolved user and updates
the current session freshness timestamp:
flask_security/oauth_glue.py:182-214flask_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:victim@example.comattacker@example.comTested version:
Flask-Security-Too 5.8.05.8.008288dff6907e413d848a16aaf43fc2c2b2a3b72
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 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"].
Source: NVD
Évaluation gratuite des vulnérabilités
Évaluez vos pratiques de sécurité cloud dans 9 domaines de sécurité pour évaluer votre niveau de risque et identifier les failles dans vos défenses.
Obtenez une démo personnalisée
"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."