{"record":{"id":"8b530df087ffa0b8","repo":"PHPOffice/PhpSpreadsheet","slug":"password-exceeds-255-characters","errorCode":null,"errorMessage":"Password exceeds 255 characters","messagePattern":"Password exceeds 255 characters","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Shared/PasswordHasher.php","lineNumber":89,"sourceCode":"\n    /**\n     * Create a password hash from a given string by a specific algorithm.\n     *\n     * 2.4.2.4 ISO Write Protection Method\n     *\n     * @see https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/1357ea58-646e-4483-92ef-95d718079d6f\n     *\n     * @param string $password Password to hash\n     * @param string $algorithm Hash algorithm used to compute the password hash value\n     * @param string $salt Pseudorandom base64-encoded string\n     * @param int $spinCount Number of times to iterate on a hash of a password\n     *\n     * @return string Hashed password\n     */\n    public static function hashPassword(string $password, string $algorithm = '', string $salt = '', int $spinCount = 10000): string\n    {\n        if (strlen($password) > self::MAX_PASSWORD_LENGTH) {\n            throw new SpException('Password exceeds ' . self::MAX_PASSWORD_LENGTH . ' characters');\n        }\n        $phpAlgorithm = self::getAlgorithm($algorithm);\n        if (!$phpAlgorithm) {\n            return self::defaultHashPassword($password);\n        }\n\n        $saltValue = base64_decode($salt);\n        $encodedPassword = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');\n\n        $hashValue = hash($phpAlgorithm, $saltValue . $encodedPassword, true);\n        for ($i = 0; $i < $spinCount; ++$i) {\n            $hashValue = hash($phpAlgorithm, $hashValue . pack('L', $i), true);\n        }\n\n        return base64_encode($hashValue);\n    }\n}\n","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Shared/PasswordHasher.php#L71-L107","documentation":"Thrown by PasswordHasher::hashPassword() when the password exceeds MAX_PASSWORD_LENGTH (255 characters). The MS-OFFCRYPTO password-verifier derivation the class implements is only defined for strings up to 255 characters, so longer input is rejected outright rather than hashed.","triggerScenarios":"Calling hashPassword($password) with strlen($password) > 255 — e.g. hashing a passphrase, a generated token, or accidental input like pasted multi-line text or a whole array-as-string; also when reading user-supplied passwords for sheet protection without an upstream length cap.","commonSituations":"Applications that reuse login passphrases (arbitrary length) as sheet-protection passwords; unit tests using long random strings; user paste errors; feeding base64 blobs where a password belonged.","solutions":["Enforce a <= 255 cap in the UI/API that collects the protection password and explain the limit.","If a longer secret is mandatory, hash/derive a <=255-byte value first (e.g. substr(sha1($secret), 0, 40)) and use that as the workbook password, documenting that the sheet password is now derived.","Trim accidental whitespace/newlines from pasted input before the length check.","Catch the exception and return a validation error rather than letting it bubble into a 500."],"exampleFix":"// before\n$hash = PasswordHasher::hashPassword($request->input('password'));\n// Password exceeds 255 characters\n\n// after\n$password = trim((string) $request->input('password'));\nif (strlen($password) > 255) {\n    throw new \\InvalidArgumentException('Sheet protection password must be at most 255 characters.');\n}\n$hash = PasswordHasher::hashPassword($password);","handlingStrategy":"validation","validationCode":"define('SHEET_PASSWORD_MAX', 255);\n$password = trim($password);\nif (strlen($password) > SHEET_PASSWORD_MAX) {\n    throw new InvalidArgumentException(\n        sprintf('Sheet password too long: %d chars (max %d).', strlen($password), SHEET_PASSWORD_MAX)\n    );\n}","typeGuard":"function sheetPasswordCandidate(mixed $pw): ?string\n{\n    return (is_string($pw) && strlen(trim($pw)) > 0 && strlen($pw) <= 255) ? $pw : null;\n}","tryCatchPattern":"try { $hash = PasswordHasher::hashPassword($password); }\ncatch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    if (str_contains($e->getMessage(), 'exceeds')) {\n        // decide policy: reject, or derive a shorter password from the secret\n        throw new DomainException('Password must be at most 255 characters.', 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Cap sheet-protection passwords at 255 in the UI/API that collects them.","If reusing long app secrets, derive a short workbook password instead of truncating silently.","Watch for paste errors (multi-line text) — trim before measuring."],"tags":["password-hashing","input-validation","sheet-protection","phpspreadsheet"],"backgroundTag":"input-length-limit","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}