Most bcrypt implementations ignore everything past 72 bytes of input. Enforce a maximum password length of 72 bytes, or move to Argon2id. Pre-hashing long passwords is possible but easy to get wrong, because of null byte truncation and password shucking.
What the limit does
OWASP's password storage guidance says bcrypt has a 72 byte input limit in most implementations and recommends enforcing a 72 byte maximum password length for bcrypt. If a user sets a 100 byte passphrase, the last 28 bytes do nothing. Two different long passwords that share the first 72 bytes hash identically.
Bytes are not characters. A password in a script with multi-byte characters reaches 72 bytes in far fewer than 72 characters, so check bytes after encoding.
Why people reach for pre-hashing
To support long passphrases, some teams hash the password first, then feed the digest to bcrypt. The idea is sound, but the details bite.
- Null bytes: a raw binary digest can contain a zero byte, and some bcrypt implementations stop reading at it. That silently shortens the effective input.
- Password shucking: if you pre-hash with a plain fast hash, an attacker who holds a leaked database of those plain fast hashes from elsewhere can strip off the bcrypt layer and attack the cheap inner hash.
OWASP notes pre-hashing is risky for these reasons.
The safer pre-hash, if you must
OWASP's suggestion is to pre-hash with HMAC-SHA-384 keyed with a pepper, then base64 encode the result before passing it to bcrypt. The key defeats shucking, because the inner value is no longer reproducible from a public hash, and base64 avoids null bytes.
Notice what this requires: a pepper stored outside the database, handled like any secret. And per the OWASP text, replacing a compromised pepper means users reset passwords.
Easier options
- Switch new accounts to Argon2id, which OWASP prefers for new work (check your library for its own input limits), and rehash existing accounts at next login.
- If you stay on bcrypt, cap password length at 72 bytes, tell users, and reject longer input instead of truncating silently.
- Audit your library. Some wrappers truncate quietly, some raise an error, and a few have already added pre-hashing. Test with a 100 byte input to find out.
A short test
Write a unit test that hashes a password of 72 bytes plus a different suffix and confirms your code either rejects it or treats the two as different. A passing result for the wrong reason, such as both silently matching, is exactly the bug.
Quick check
Should I just truncate long passwords myself?
Silent truncation surprises users and weakens long passphrases. Rejecting input over the limit with a clear message is more honest.
Is bcrypt unsafe?
OWASP lists it for legacy systems with a work factor of at least 10, and prefers Argon2id for new work. It is acceptable with care, not a first choice.
Safeguard's dependency scanning can show which password hashing libraries and versions you ship, and the free scan at gold.safeguard.sh/scan is a quick place to start.
Sources
Last reviewed: 19 October 2026.