{"record":{"id":"d4ff63059c22ad75","repo":"spring-projects/spring-security","slug":"encoded-password-does-not-look-like-bcrypt","errorCode":null,"errorMessage":"Encoded password does not look like BCrypt","messagePattern":"Encoded password does not look like BCrypt","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java","lineNumber":126,"sourceCode":"\t\tthis.version = version;\n\t\tthis.strength = (strength == -1) ? 10 : strength;\n\t\tthis.random = (random != null) ? () -> random : SecureRandomHolder::getInstance;\n\t}\n\n\t@Override\n\tprotected String encodeNonNullPassword(String rawPassword) {\n\t\tString salt = getSalt();\n\t\treturn BCrypt.hashpw(rawPassword.toString(), salt);\n\t}\n\n\tprivate String getSalt() {\n\t\treturn BCrypt.gensalt(this.version.getVersion(), this.strength, this.random.get());\n\t}\n\n\t@Override\n\tprotected boolean matchesNonNull(String rawPassword, String encodedPassword) {\n\t\tif (!this.BCRYPT_PATTERN.matcher(encodedPassword).matches()) {\n\t\t\tthis.logger.warn(\"Encoded password does not look like BCrypt\");\n\t\t\treturn false;\n\t\t}\n\t\treturn BCrypt.checkpw(rawPassword.toString(), encodedPassword);\n\t}\n\n\t@Override\n\tprotected boolean upgradeEncodingNonNull(String encodedPassword) {\n\t\tMatcher matcher = this.BCRYPT_PATTERN.matcher(encodedPassword);\n\t\tif (!matcher.matches()) {\n\t\t\tthrow new IllegalArgumentException(\"Encoded password does not look like BCrypt: \" + encodedPassword);\n\t\t}\n\t\tint strength = Integer.parseInt(matcher.group(2));\n\t\treturn strength < this.strength;\n\t}\n\n\t/**\n\t * Stores the default bcrypt version for use in configuration.\n\t *","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCryptPasswordEncoder.java#L108-L144","documentation":"BCryptPasswordEncoder.matchesNonNull logs this warning when the encoded password does not match the BCrypt pattern (roughly \\$2(a|y|b)?\\$\\d{2}\\$[./0-9A-Za-z]{53}). The string cannot be a BCrypt hash, so BCrypt.checkpw would throw; the encoder logs and returns false instead.","triggerScenarios":"Calling matches(rawPassword, encodedPassword) where encodedPassword is plaintext, a SHA/MD5 hex digest, an Argon2/PBKDF2 hash, or an empty/whitespace string — anything not matching the $2[aby]$ cost$ salt+hash layout.","commonSituations":"Users created before a migration to BCrypt whose hashes are SHA-1/MD5; plaintext credentials seeded into the database; hashes prefixed with an encoder id like {bcrypt} passed to BCryptPasswordEncoder directly; a DB column truncating the hash.","solutions":["Confirm the stored value is a BCrypt hash: 60 chars, starts with $2a$, $2b$, or $2y$.","If the value carries a prefix like {bcrypt}, switch to DelegatingPasswordEncoder and store it without passing raw prefixed strings to BCryptPasswordEncoder.","Migrate legacy hashes: store them with an appropriate prefix via PasswordEncoderFactories, or re-encode via a login-time upgrade (PasswordEncoder.upgradeEncoding / re-encode on successful auth).","Check the column length (CHAR(60) or larger) so hashes are not truncated."],"exampleFix":"// before\nBCryptPasswordEncoder enc = new BCryptPasswordEncoder();\nboolean ok = enc.matches(raw, \"{bcrypt}$2a$10$...\"); // warns, always false\n\n// after\nPasswordEncoder enc = PasswordEncoderFactories.createDelegatingPasswordEncoder();\nboolean ok = enc.matches(raw, \"{bcrypt}$2a$10$...\");","handlingStrategy":"validation","validationCode":"private static final Pattern BCRYPT = Pattern.compile(\"\\\\A\\\\$2(a|y|b)?\\\\$\\\\d{2}\\\\$[./0-9A-Za-z]{53}\\\\z\");\nboolean looksLikeBcrypt = encoded != null && BCRYPT.matcher(encoded).matches();","typeGuard":null,"tryCatchPattern":"BCrypt.checkpw can throw IllegalArgumentException on malformed input; if calling BCrypt directly, wrap it: try { return BCrypt.checkpw(raw, encoded); } catch (IllegalArgumentException e) { log.warn(...); return false; }","preventionTips":["Always create users through passwordEncoder.encode(rawPassword).","Reserve CHAR(60)/VARCHAR(60+) for BCrypt columns to prevent truncation.","Prefer DelegatingPasswordEncoder so format is carried in the {id} prefix and mismatches are explicit.","On successful login, re-encode and persist if upgradeEncoding() is true to migrate legacy hashes."],"tags":["spring-security","bcrypt","password-encoding","authentication"],"backgroundTag":"invalid-argument-format","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}