ory/kratos · error · ErrHashParametersOutOfBounds

bcrypt cost= exceeds max

Error message

bcrypt cost=%d exceeds max %d

What it means

validateBcryptHashCost parsed the cost parameter embedded in an existing bcrypt hash (during comparison or import validation) and found it above the compiled-in maxBcryptCost limit. The wrapped sentinel ErrHashParametersOutOfBounds marks this as an out-of-bounds hashing parameter; the fault is in the stored/imported hash, not in user input.

Solutions

  1. Regenerate the offending hash with a cost within the allowed maximum
  2. If the high cost is intentional and policy allows, raise maxBcryptCost and rebuild
  3. Reject or skip the imported credential hash that carries the excessive cost
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at hash/hash_limits.go:131 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/e9a5373828e73a7d. Report an issue: GitHub.

Appendix: source

Thrown at hash/hash_limits.go:131

		return errors.Wrapf(ErrHashParametersOutOfBounds, "argon2 p=%d not in [1, %d]", parallelism, maxArgon2Parallelism)
	}
	return nil
}

func validatePbkdf2Params(iterations uint32) error {
	if iterations == 0 || iterations > maxPbkdf2Iterations {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "pbkdf2 i=%d not in [1, %d]", iterations, maxPbkdf2Iterations)
	}
	return nil
}

func validateBcryptHashCost(hashed []byte) error {
	cost, err := bcrypt.Cost(hashed)
	if err != nil {
		return err
	}
	if cost > maxBcryptCost {
		return errors.Wrapf(ErrHashParametersOutOfBounds, "bcrypt cost=%d exceeds max %d", cost, maxBcryptCost)
	}
	return nil
}

// ValidateImportedHash performs cost-parameter bounds checking on a hash
// before it is persisted via the admin identity import API. It is the
// import-time counterpart to the bounds checks in the compare* paths and
// exists so we fail fast on malicious imports rather than persisting a hash
// that would crash the process at every login attempt.
//
// Hashers without attacker-controlled cost parameters (md5-crypt, sha-crypt,
// the static SHA/MD5/HMAC families, SSHA) pass through unchanged.
func ValidateImportedHash(hashed []byte) error {
	switch {
	case IsBcryptHash(hashed):
		return validateBcryptHashCost(hashed)
	case IsArgon2idHash(hashed), IsArgon2iHash(hashed):
		_, _, _, err := decodeArgon2idHash(string(hashed))

View on GitHub (pinned to b86338da04)