Skip to content

Keep authentication fail-closed when provider filters change between lookups #943

Description

@chubes4

Security problem

Authentication can fail open when two_factor_providers returns different provider sets across the multiple lookups performed during one request. A user with persisted enabled 2FA can be treated as not using 2FA, leaving auth cookies enabled and REST/XML-RPC password authentication unrestricted.

Minimized call schedule

For one enabled provider, make successive provider-filter snapshots follow:

[present, absent, present]

Observed flow around class-two-factor-core.php:702-735, :822-875, and :936-953:

  1. Initial supported-provider lookup includes the provider.
  2. Availability lookup excludes it and returns an empty array rather than a durable error state.
  3. Enabled-provider lookup includes it again.
  4. is_user_using_two_factor() returns false.
  5. filter_authenticate() does not enforce the second factor.

Evidence

Found during an isolated aggressive multisite fuzz campaign against #933:

  • 50,001 randomized provider states across three deterministic seeds
  • 5,000 transition sequences / 15,000 cross-site steps
  • Reproduced on PHP 7.4 + WordPress 6.9 and PHP 8.3 + WordPress trunk
  • Seeds observed 998/51 and 959/48 claimed-state/cookie fail-open events
  • No production traffic or state used

Expected

Provider resolution used for one authentication decision must derive from one consistent snapshot or otherwise preserve a durable fail-closed state. Dynamic provider deregistration/re-registration during the request must never downgrade an account with persisted 2FA claims to password-only authentication.

Related: #933 fixes a fatal under a different provider-removal schedule, but this authentication issue appears to predate its latest commit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions