Back to Checks
okta

Every active Okta Password Policy requires at least one uppercase character

authenticator_password_complexity_uppercase
Service: authenticatorSeverity: low
OfficialBuilt-inVerified
Categories:identity-access
Resource Type:NotDefined

Every active Okta Password Policy must require at least one uppercase character in the user's password.

Okta evaluates Password Policies by group assignment, so a permissive custom policy that drops uppercase complexity can govern users even when the default policy is compliant. The check emits one finding per active policy so weaker custom policies do not hide behind a compliant default.

Risk

Without uppercase complexity, the effective alphabet shrinks and passwords become easier to enumerate.

  • Brute force succeeds against a smaller character space
  • Wordlist attacks match more candidates without case mixing
  • Inconsistent baselines leave users on legacy policies with weaker complexity than the default

Run this check with Prowler

Run in Prowler Cloud
Run
prowler okta --checks authenticator_password_complexity_uppercase

Recommendation

Configure every active Okta Password Policy so:

  • Minimum number of uppercase characters is 1 or more
  • Group assignments do not route users to legacy policies that disable uppercase complexity

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_min_uppercase = 1  # Critical: STIG-aligned complexity
}

Other

1Sign in to the **Okta Admin Console** as a *Super Admin*.
2Navigate to **Security** > **Authentication** > **Password**.
3For every active policy, click **Edit** and enable **Upper case letter** under *Complexity*.
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_complexity_uppercase(Check):
    """STIG V-273196 / OKTA-APP-000670.

    Every active Okta Password Policy must require at least one uppercase character.
    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 = "at least one uppercase character"
        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.min_upper_case is not None and policy.min_upper_case >= 1:
                report.status = "PASS"
                report.status_extended = (
                    f"{password_policy_label(policy)} enforces {requirement} "
                    f"(minimum uppercase characters: {policy.min_upper_case})."
                )
            else:
                report.status = "FAIL"
                report.status_extended = (
                    f"{password_policy_label(policy)} does not enforce {requirement} "
                    f"(minimum uppercase characters: {policy.min_upper_case})."
                )
            findings.append(report)
        return findings