“There’s always a side door.”

Overview#

I discovered an account takeover vulnerability in django-allauth, one of the most widely-used authentication libraries for Django. The vulnerability allows an attacker to impersonate arbitrary users by exploiting how certain OAuth providers’ identifiers are resolved.

Vulnerability Details#

CVE: CVE-2025-65431 Type: Improper Authentication / Account Takeover (CWE-287) Impact: Account Impersonation Affected Versions: django-allauth < 65.13.0

The Bug#

Both the Okta and NetIQ providers were using preferred_username as the identifier for third-party provider accounts. This value is mutable — users can change their preferred_username on the identity provider side.

This means:

  1. Victim authenticates via Okta/NetIQ, django-allauth stores preferred_username as their provider UID
  2. Attacker changes their own preferred_username on the identity provider to match the victim’s stored value
  3. Attacker authenticates — django-allauth matches them to the victim’s account
  4. Full account takeover

Why It Matters#

The core issue is using a mutable, user-controlled value for authorization decisions. OAuth providers typically expose multiple identifier fields:

FieldMutableSafe for Auth
sub (subject)NoYes
emailSometimesRisky
preferred_usernameYesNo

The sub claim is the only identifier guaranteed to be immutable and unique per provider. Using anything else for account binding is a security anti-pattern.

Fix#

Fixed in django-allauth 65.13.0. The Okta and NetIQ providers now use immutable identifiers (sub) instead of preferred_username for account resolution.

References#

Timeline#

DateEvent
2024Vulnerability discovered
2024-12-25Fix released in django-allauth 65.3.1
2025CVE-2025-65431 assigned

Responsible disclosure was followed.