Skip to content

Fix overflow in AccessFailedAsync when DefaultLockoutTimeSpan is large#67647

Open
GOVINSAGA wants to merge 1 commit into
dotnet:mainfrom
GOVINSAGA:fix/60181-lockout-timespan-overflow
Open

Fix overflow in AccessFailedAsync when DefaultLockoutTimeSpan is large#67647
GOVINSAGA wants to merge 1 commit into
dotnet:mainfrom
GOVINSAGA:fix/60181-lockout-timespan-overflow

Conversation

@GOVINSAGA

Copy link
Copy Markdown

Summary

Fixes #60181.

UserManager.AccessFailedAsync sets the lockout end date with:

UtcNow().Add(Options.Lockout.DefaultLockoutTimeSpan)

When DefaultLockoutTimeSpan is large enough that the result exceeds DateTimeOffset.MaxValue, this throws ArgumentOutOfRangeException. A legitimate scenario is setting DefaultLockoutTimeSpan = TimeSpan.MaxValue to lock an account out indefinitely (e.g. after repeated failed MFA attempts). Today that crashes instead of locking the user out.

Change

Clamp the computed lockout end date to DateTimeOffset.MaxValue when the configured timespan would overflow:

var now = UtcNow();
var lockoutEndDate = Options.Lockout.DefaultLockoutTimeSpan < DateTimeOffset.MaxValue - now
    ? now.Add(Options.Lockout.DefaultLockoutTimeSpan)
    : DateTimeOffset.MaxValue;

The overflow check computes headroom as DateTimeOffset.MaxValue - now (always a valid TimeSpan), so the check itself cannot overflow.

Tests

Adds LockoutWithMaxTimeSpanDoesNotOverflow to the shared UserManagerSpecificationTestBase suite, so every store implementation (in-memory, EF Core) is covered. It sets DefaultLockoutTimeSpan = TimeSpan.MaxValue, triggers a lockout via AccessFailedAsync, and asserts the call succeeds and the lockout end date is DateTimeOffset.MaxValue.

UserManager.AccessFailedAsync computed the lockout end date as
UtcNow().Add(DefaultLockoutTimeSpan), which throws
ArgumentOutOfRangeException when the resulting DateTimeOffset would exceed
DateTimeOffset.MaxValue (for example when DefaultLockoutTimeSpan is set to
TimeSpan.MaxValue to lock an account out indefinitely).

Clamp the lockout end date to DateTimeOffset.MaxValue when the configured
timespan would overflow. The overflow check subtracts the current time from
DateTimeOffset.MaxValue (always a valid TimeSpan) to avoid overflowing while
performing the check itself.

Adds a regression test to the shared UserManager specification suite so all
store implementations are covered.

Fixes dotnet#60181

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 7, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @GOVINSAGA. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UserManager.AccessFailedAsync results in overflow if DefaultLockoutTimeSpan is too large

1 participant