{"record":{"id":"7a3bbafcdb641f75","repo":"spring-projects/spring-security","slug":"bad-number-of-rounds","errorCode":null,"errorMessage":"Bad number of rounds","messagePattern":"Bad number of rounds","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java","lineNumber":515,"sourceCode":"\t\t\tlr[0] ^= streamtoword(data, doffp);\n\t\t\tlr[1] ^= streamtoword(data, doffp);\n\t\t\tencipher(lr, 0);\n\t\t\tthis.P[i] = lr[0];\n\t\t\tthis.P[i + 1] = lr[1];\n\t\t}\n\n\t\tfor (i = 0; i < slen; i += 2) {\n\t\t\tlr[0] ^= streamtoword(data, doffp);\n\t\t\tlr[1] ^= streamtoword(data, doffp);\n\t\t\tencipher(lr, 0);\n\t\t\tthis.S[i] = lr[0];\n\t\t\tthis.S[i + 1] = lr[1];\n\t\t}\n\t}\n\n\tstatic long roundsForLogRounds(int log_rounds) {\n\t\tif (log_rounds < 4 || log_rounds > 31) {\n\t\t\tthrow new IllegalArgumentException(\"Bad number of rounds\");\n\t\t}\n\t\treturn 1L << log_rounds;\n\t}\n\n\t/**\n\t * Perform the central password hashing step in the bcrypt scheme\n\t * @param password the password to hash\n\t * @param salt the binary salt to hash with the password\n\t * @param log_rounds the binary logarithm of the number of rounds of hashing to apply\n\t * @param sign_ext_bug true to implement the 2x bug\n\t * @param safety bit 16 is set when the safety measure is requested\n\t * @return an array containing the binary hashed password\n\t */\n\tprivate byte[] crypt_raw(byte password[], byte salt[], int log_rounds, boolean sign_ext_bug, int safety,\n\t\t\tboolean for_check) {\n\t\tint cdata[] = bf_crypt_ciphertext.clone();\n\t\tint clen = cdata.length;\n","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java#L497-L533","documentation":"roundsForLogRounds converts the bcrypt cost factor (log_rounds) to an iteration count and throws this IllegalArgumentException when log_rounds is outside the valid 4..31 range. Bcrypt requires at least 2^4 iterations; the upper bound prevents overflow of the 1L << log_rounds computation.","triggerScenarios":"Passing a cost factor below 4 or above 31 to gensalt (e.g. gensalt(2) or gensalt(40)), or parsing a hash whose cost segment is outside that range via hashpw -> crypt_raw -> roundsForLogRounds.","commonSituations":"Misreading strength as a linear value (using 10..16 incorrectly is fine, but 0/1/2 is not); loading a configurable strength from properties where the default is 0; a stored hash with a corrupted cost field.","solutions":["Pass a log-rounds value between 4 and 31 (10 is the common default) to BCryptPasswordEncoder/gensalt","If strength comes from config, clamp or validate it: Math.max(4, Math.min(31, strength))","Fix the stored hash or regenerate it if its cost segment is corrupt"],"exampleFix":"// before\nint strength = Integer.parseInt(props.getProperty(\"bcrypt.strength\", \"0\"));\n// after\nint strength = Math.max(4, Math.min(31, Integer.parseInt(props.getProperty(\"bcrypt.strength\", \"10\"))));","handlingStrategy":"validation","validationCode":"static int sanitizeStrength(int strength) {\n    if (strength < 4 || strength > 31) throw new IllegalArgumentException(\"bcrypt strength must be 4..31, got \" + strength);\n    return strength;\n}","typeGuard":null,"tryCatchPattern":"try {\n    String salt = BCrypt.gensalt(strength);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Bad number of rounds\")) {\n        strength = 10; // fall back to default cost\n        salt = BCrypt.gensalt(strength);\n    } else throw e;\n}","preventionTips":["Provide a sane default strength (10) in configuration with explicit bounds","Clamp or fail-fast on config-loaded strength values at startup","Remember strength is a log2 cost factor, not a linear count"],"tags":["bcrypt","cost-factor","input-validation","java","spring-security"],"backgroundTag":"value-out-of-range","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}