{"record":{"id":"029ba76e02810cef","repo":"spring-projects/spring-security","slug":"invalid-maxolen","errorCode":null,"errorMessage":"Invalid maxolen","messagePattern":"Invalid maxolen","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java","lineNumber":285,"sourceCode":"\t\treturn index_64[x];\n\t}\n\n\t/**\n\t * Decode a string encoded using bcrypt's base64 scheme to a byte array. Note that\n\t * this is *not* compatible with the standard MIME-base64 encoding.\n\t * @param s the string to decode\n\t * @param maxolen the maximum number of bytes to decode\n\t * @return an array containing the decoded bytes\n\t * @throws IllegalArgumentException if maxolen is invalid\n\t */\n\tstatic byte[] decode_base64(String s, int maxolen) throws IllegalArgumentException {\n\t\tStringBuilder rs = new StringBuilder();\n\t\tint off = 0, slen = s.length(), olen = 0;\n\t\tbyte ret[];\n\t\tbyte c1, c2, c3, c4, o;\n\n\t\tif (maxolen <= 0) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid maxolen\");\n\t\t}\n\n\t\twhile (off < slen - 1 && olen < maxolen) {\n\t\t\tc1 = char64(s.charAt(off++));\n\t\t\tc2 = char64(s.charAt(off++));\n\t\t\tif (c1 == -1 || c2 == -1) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\to = (byte) (c1 << 2);\n\t\t\to |= (c2 & 0x30) >> 4;\n\t\t\trs.append((char) o);\n\t\t\tif (++olen >= maxolen || off >= slen) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc3 = char64(s.charAt(off++));\n\t\t\tif (c3 == -1) {\n\t\t\t\tbreak;\n\t\t\t}","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/bcrypt/BCrypt.java#L267-L303","documentation":"BCrypt.decode_base64() decodes bcrypt-alphabet strings into at most maxolen bytes. It throws this IllegalArgumentException when maxolen <= 0, because a non-positive output length is meaningless. Called from hashpw when parsing the salt portion of a bcrypt hash string.","triggerScenarios":"Calling decode_base64 (directly or via hashpw) with maxolen <= 0 — e.g. parsing a hash string where the computed salt length came out as 0 because the input hash string was malformed or empty.","commonSituations":"Passing a malformed/empty salt string to hashpw(); truncation of stored hashes; manual parsing of bcrypt strings producing a wrong length.","solutions":["Ensure the input to hashpw is a complete bcrypt hash like '$2a$10$<22-char-salt>' so the derived salt length is positive","Validate the hash format with a regex (e.g. \\\\A\\\\$2(a|y|b)?\\\\$\\\\d{2}\\\\$[./A-Za-z0-9]{53}) before parsing","If calling decode_base64 directly, pass a maxolen >= 1 and <= expected output size"],"exampleFix":"// before\nbyte[] salt = BCrypt.decode_base64(saltPart, 0); // maxolen <= 0\n// after\nif (saltPart.length() < 22) throw new IllegalArgumentException(\"salt too short\");\nbyte[] salt = BCrypt.decode_base64(saltPart, 16);","handlingStrategy":"validation","validationCode":"static boolean isBcryptHashFormat(String s) {\n    return s != null && s.matches(\"\\\\\\\\A\\\\\\\\$2(a|y|b)?\\\\\\\\$\\\\\\\\d{2}\\\\\\\\$[./A-Za-z0-9]{53}\\\\\\\\z\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return BCrypt.hashpw(raw, storedHash);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"maxolen\")) {\n        log.warn(\"Malformed bcrypt hash: salt segment too short\");\n        return false;\n    }\n    throw e;\n}","preventionTips":["Regex-validate stored bcrypt hashes before calling hashpw for verification","Never truncate or trim hash strings in transit (avoid lossy charsets/trimming)","Pass full hashes to BCrypt.checkpw rather than extracting segments manually"],"tags":["bcrypt","base64","input-validation","java","spring-security"],"backgroundTag":"invalid-argument-value","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"}