Back to Checks
okta

Every active Okta Password Policy locks accounts after 3 or fewer failed attempts

authenticator_password_lockout_threshold_3
Service: authenticatorSeverity: medium
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:NotDefined

Every active Okta Password Policy must lock the account after at most 3 consecutive failed sign-in attempts.

Okta evaluates Password Policies by group assignment, so a permissive custom policy with a higher threshold (or no lockout) can govern users even when the default is compliant. The check emits one finding per active policy.

Risk

A high lockout threshold (or no threshold) leaves accounts exposed to online password guessing.

  • Online brute force retains enough attempts to enumerate common passwords
  • Credential stuffing can iterate through breached credentials at scale
  • Inconsistent baselines leave users on legacy policies with weaker thresholds than the default

Run this check with Prowler

Run in Prowler Cloud
Run
prowler okta --checks authenticator_password_lockout_threshold_3

Recommendation

Configure every active Okta Password Policy so:

  • Lock out user after X unsuccessful attempts is 3 or fewer
  • Group assignments do not route users to legacy policies with higher thresholds or no lockout

Review each active Password Policy individually — the check evaluates them one at a time.

Remediation

Terraform

resource "okta_policy_password" "<example_resource_name>" {
  name                  = "<example_resource_name>"
  status                = "ACTIVE"
  password_max_lockout_attempts = 3  # Critical: STIG-aligned lockout threshold
}

Other

1Sign in to the **Okta Admin Console** as a *Super Admin*.
2Navigate to **Security** > **Authentication** > **Password**.
3For every active policy, click **Edit** and set *Lock out user after X unsuccessful attempts* to `3` or fewer.
4Save the policy.
5Repeat for every active Password Policy returned by the check.

Check Code

from prowler.lib.check.models import Check, CheckReportOkta
from prowler.providers.okta.services.authenticator.authenticator_client import (
    authenticator_client,
)
from prowler.providers.okta.services.authenticator.lib.password_policy_helpers import (
    active_password_policies,
    missing_password_policies_scope_finding,
    no_active_password_policies_finding,
    password_policy_label,
)


class authenticator_password_lockout_threshold_3(Check):
    """STIG V-273189 / OKTA-APP-000170.

    Every active Okta Password Policy must lock accounts after no more than 3 consecutive failed login attempts.
    The check emits one finding per active policy so a weaker
    custom policy cannot hide behind a compliant default.
    """

    def execute(self) -> list[CheckReportOkta]:
        """Evaluate all active Okta Password Policies."""
        findings = []
        org_domain = authenticator_client.provider.identity.org_domain
        requirement = "password lockout after 3 or fewer failed attempts"
        missing_scope = authenticator_client.missing_scope.get("password_policies")

        if missing_scope:
            return [
                missing_password_policies_scope_finding(
                    self.metadata(), org_domain, missing_scope, requirement
                )
            ]

        policies = active_password_policies(authenticator_client.password_policies)
        if not policies:
            return [
                no_active_password_policies_finding(
                    self.metadata(), org_domain, requirement
                )
            ]

        for policy in policies:
            report = CheckReportOkta(
                metadata=self.metadata(), resource=policy, org_domain=org_domain
            )
            if policy.max_attempts is not None and policy.max_attempts <= 3:
                report.status = "PASS"
                report.status_extended = (
                    f"{password_policy_label(policy)} enforces {requirement} "
                    f"(maximum failed attempts: {policy.max_attempts})."
                )
            else:
                report.status = "FAIL"
                report.status_extended = (
                    f"{password_policy_label(policy)} does not enforce {requirement} "
                    f"(maximum failed attempts: {policy.max_attempts})."
                )
            findings.append(report)
        return findings