spring-projects/spring-security · error · IllegalArgumentException

Bad strength

Error message

Bad strength

What it means

The BCryptPasswordEncoder constructor validates the requested strength (log rounds) when explicitly provided. It must be either -1 (meaning 'use the default of 10') or within BCrypt.MIN_LOG_ROUNDS (4) to BCrypt.MAX_LOG_ROUNDS (31). Anything else throws IllegalArgumentException at construction time.

Source

Thrown at crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java:106

	/**
	 * Creates a new instance using the given bcrypt version and strength.
	 * @param version the version of bcrypt, can be 2a,2b,2y
	 * @param strength the log rounds to use, between 4 and 31
	 */
	public BCryptPasswordEncoder(BCryptVersion version, int strength) {
		this(version, strength, null);
	}

	/**
	 * Creates a new instance using the given bcrypt version, strength, and secure random
	 * instance.
	 * @param version the version of bcrypt, can be 2a,2b,2y
	 * @param strength the log rounds to use, between 4 and 31
	 * @param random the secure random instance to use
	 */
	public BCryptPasswordEncoder(BCryptVersion version, int strength, @Nullable SecureRandom random) {
		if (strength != -1 && (strength < BCrypt.MIN_LOG_ROUNDS || strength > BCrypt.MAX_LOG_ROUNDS)) {
			throw new IllegalArgumentException("Bad strength");
		}
		this.version = version;
		this.strength = (strength == -1) ? 10 : strength;
		this.random = (random != null) ? () -> random : SecureRandomHolder::getInstance;
	}

	@Override
	protected String encodeNonNullPassword(String rawPassword) {
		String salt = getSalt();
		return BCrypt.hashpw(rawPassword.toString(), salt);
	}

	private String getSalt() {
		return BCrypt.gensalt(this.version.getVersion(), this.strength, this.random.get());
	}

	@Override
	protected boolean matchesNonNull(String rawPassword, String encodedPassword) {

View on GitHub (pinned to 96852e8860)

Solutions

  1. Use a strength between 4 and 31 (or -1 for the default).
  2. Validate the configured integer before constructing the encoder.
  3. Omit the strength parameter and use the no-arg or (version) constructor if defaults are fine.

Example fix

// before
int strength = Integer.parseInt(env.getProperty("security.bcrypt.strength"));
PasswordEncoder encoder = new BCryptPasswordEncoder(BCryptVersion.$2A, strength);
// after
int raw = Integer.parseInt(env.getProperty("security.bcrypt.strength"));
if (raw != -1 && (raw < 4 || raw > 31)) throw new IllegalStateException("bcrypt strength must be 4-31 or -1");
PasswordEncoder encoder = new BCryptPasswordEncoder(BCryptVersion.$2A, raw);
Defensive patterns

Strategy: validation

Validate before calling

if (strength != -1 && (strength < 4 || strength > 31)) throw new IllegalStateException("strength must be 4-31 or -1: " + strength);

Try / catch

try { encoder = new BCryptPasswordEncoder(version, strength, random); } catch (IllegalArgumentException e) { throw new IllegalStateException("Invalid bcrypt strength configuration: " + strength, e); }

Prevention

When it happens

Trigger: new BCryptPasswordEncoder(BCryptVersion.$2A, strength, random) where strength is, e.g., 0, 3, 32, or 100 — typically from externalized configuration or a computed value — while not being exactly -1.

Common situations: Spring @Value("${bcrypt.strength}") injecting an unvalidated property; storing strength as a percentage (e.g. 80); front-end sending cost as bits instead of rounds; typos like -11.

Related errors


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/27b9ce2cda98a10a. Report an issue: GitHub.