{"record":{"id":"7ea4570bc3124f32","repo":"spring-projects/spring-security","slug":"couldn-t-find-closing-brace-for-sha-prefix","errorCode":null,"errorMessage":"Couldn't find closing brace for SHA prefix","messagePattern":"Couldn't find closing brace for SHA prefix","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java","lineNumber":177,"sourceCode":"\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}\n\n\tpublic void setForceLowerCasePrefix(boolean forceLowerCasePrefix) {\n\t\tthis.forceLowerCasePrefix = forceLowerCasePrefix;\n\t}\n\n}\n","sourceCodeStart":159,"sourceCodeEnd":187,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java#L159-L187","documentation":"extractPrefix parses the {prefix} header of an encoded password. If the string starts with '{' but contains no '}', lastIndexOf returns -1 and this IllegalArgumentException is thrown. The stored hash is malformed — an opening brace without its closing brace — so the prefix cannot be determined.","triggerScenarios":"Calling encode/matches with an encodedPassword like \"{SSHAabc123...\" where the closing '}' after the algorithm name was lost due to truncation, manual editing, or a broken import.","commonSituations":"Database column too short truncating the stored hash right after '{'; copy/paste dropping the brace; hand-written seed fixtures with malformed prefixes.","solutions":["Inspect the stored value and restore the full hash including the closing '}' (e.g. \"{SSHA}base64hashsalt\").","Re-encode the password with LdapShaPasswordEncoder and replace the corrupted entry.","Widen the storage column or fix the import/export code that truncates hashes."],"exampleFix":"// before\nString stored = \"{SSHAbXcgLi4u\"; // missing '}'\n// after\nString stored = \"{SSHA}bXcgLi4uZXhhbXBsZQ==\";","handlingStrategy":"validation","validationCode":"boolean wellFormed = stored.startsWith(\"{\") && stored.indexOf('}') > 0;\nif (!wellFormed) throw new IllegalArgumentException(\"stored hash missing '{...}' prefix\");","typeGuard":null,"tryCatchPattern":"try {\n    ok = ldapEncoder.matches(raw, stored);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"closing brace\")) {\n        // mark record corrupted and force password reset\n    }\n}","preventionTips":["Size hash storage columns generously (e.g. VARCHAR(255)) so hashes are never truncated.","Validate stored hashes match the regex ^\\{[A-Za-z]+\\}.+ at import time."],"tags":["java","spring-security","ldap","parsing"],"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"}