{"record":{"id":"ad727b44283d48fa","repo":"spring-projects/spring-security","slug":"unsupported-password-prefix-prefix","errorCode":null,"errorMessage":"Unsupported password prefix '{prefix}'","messagePattern":"Unsupported password prefix '(.+?)'","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java","lineNumber":162,"sourceCode":"\t */\n\t@Override\n\tprotected boolean matchesNonNull(String rawPassword, String encodedPassword) {\n\t\tString prefix = extractPrefix(encodedPassword);\n\t\tif (prefix == null) {\n\t\t\treturn PasswordEncoderUtils.equals(encodedPassword, rawPassword);\n\t\t}\n\t\tbyte[] salt = getSalt(encodedPassword, prefix);\n\t\tint startOfHash = prefix.length();\n\t\tString encodedRawPass = encode(rawPassword, salt).substring(startOfHash);\n\t\treturn PasswordEncoderUtils.equals(encodedRawPass, encodedPassword.substring(startOfHash));\n\t}\n\n\tprivate byte @Nullable [] getSalt(String encodedPassword, String prefix) {\n\t\tif (prefix.equals(SSHA_PREFIX) || prefix.equals(SSHA_PREFIX_LC)) {\n\t\t\treturn extractSalt(encodedPassword);\n\t\t}\n\t\tif (!prefix.equals(SHA_PREFIX) && !prefix.equals(SHA_PREFIX_LC)) {\n\t\t\tthrow new IllegalArgumentException(\"Unsupported password prefix '\" + prefix + \"'\");\n\t\t}\n\t\t// Standard SHA\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the hash prefix or null if there isn't one.\n\t */\n\tprivate @Nullable String extractPrefix(String encPass) {\n\t\tif (!encPass.startsWith(\"{\")) {\n\t\t\treturn null;\n\t\t}\n\t\tint secondBrace = encPass.lastIndexOf('}');\n\t\tif (secondBrace < 0) {\n\t\t\tthrow new IllegalArgumentException(\"Couldn't find closing brace for SHA prefix\");\n\t\t}\n\t\treturn encPass.substring(0, secondBrace + 1);\n\t}","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java#L144-L180","documentation":"During matches(), getSalt examines the prefix extracted from the encoded password and throws this IllegalArgumentException when the prefix is neither {SHA}, {SSHA} nor their lowercase variants. It means the stored password was not produced by LdapShaPasswordEncoder (or was corrupted), so salt extraction — and therefore comparison — cannot proceed.","triggerScenarios":"Calling matches(rawPassword, encodedPassword) where encodedPassword has a different or unrecognized brace prefix such as {bcrypt}, {CRYPT}, or no prefix format the encoder understands.","commonSituations":"A password store migrated between encoders (e.g. from bcrypt to LDAP SHA or vice versa) with stale entries; manually edited seed data with a typo in the prefix; DelegatingPasswordEncoder-style {id} hashes passed to this encoder directly.","solutions":["Only feed this encoder hashes it produced: strings starting with {SHA} or {SSHA} (or lowercase forms).","Re-encode the user's password with LdapShaPasswordEncoder and update the stored value.","Use DelegatingPasswordEncoder to route each stored hash to the encoder matching its prefix instead of hard-wiring LdapShaPasswordEncoder."],"exampleFix":"// before\nboolean ok = ldapEncoder.matches(raw, stored); // stored = \"{bcrypt}$2a$...\"\n// after\nPasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();\nboolean ok = encoder.matches(raw, stored);","handlingStrategy":"validation","validationCode":"if (!(stored.startsWith(\"{SHA}\") || stored.startsWith(\"{SSHA}\")\n        || stored.startsWith(\"{sha}\") || stored.startsWith(\"{ssha}\"))) {\n    throw new IllegalArgumentException(\"not an LDAP SHA/SSHA hash: \" + prefixOf(stored));\n}\nboolean ok = ldapEncoder.matches(raw, stored);","typeGuard":null,"tryCatchPattern":"try {\n    ok = ldapEncoder.matches(raw, stored);\n} catch (IllegalArgumentException e) {\n    // unsupported prefix: route to the appropriate encoder or flag the record\n}","preventionTips":["Use DelegatingPasswordEncoder so {id}-prefixed hashes reach the right encoder automatically.","Never manually edit stored hashes; regenerate them with the intended encoder."],"tags":["java","spring-security","ldap","password-hashing"],"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-14T16:17:12.679Z"}