RUSTSEC-2026-0199 Panic in `bcrypt::verify` on non-ASCII hash input
Attackers can crash Rust applications by supplying non-ASCII bcrypt hashes, causing a panic in the verification logic.
- Exploited in the wild
- Not known
- Login needed
- Not needed
- Attackable
- Over the internet
- Victim action needed
- Not needed
- Fix
- Available
What is RUSTSEC-2026-0199?
RUSTSEC-2026-0199 is a denial of service vulnerability in bcrypt, published on 20 Jun 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.
Official description
bcrypt::verify(password, hash) and HashParts::from_str(hash) panic in
str::slice_error_fail when given a 60-byte &str containing a multi-byte
UTF-8 character at certain byte positions.
Impact
Any Rust code that calls bcrypt::verify (or HashParts::from_str) with an
attacker-controlled hash string will panic. The bcrypt crate is
#![forbid(unsafe_code)], so this is limited to a denial-of-service and
cannot lead to memory corruption.
Realistic attack contexts include:
- Rust authentication services reading hashes from a database that was previously compromised via, e.g., SQL injection. The attacker can then crash the service on every login attempt against the tampered account.
- CLI tools accepting hashes from stdin or command-line arguments.
- Password managers or vault services loading hashes from untrusted configuration sources.
Root cause
split_hash performed five &str slicing operations on the input hash:
&hash[1..3], &hash[4..6], &hash[7..], &salt_and_hash[..22], and
&salt_and_hash[22..]. None of these were char-boundary-checked. Any input
where a multi-byte UTF-8 character spanned one of those byte positions
caused a panic.
This is a regression of the fix originally shipped in 2021 for issue #62
(commit 0833509). The regression was introduced in the parser rewrite in
PR #95 (commit e9a8394, released as 0.19.0).
The pre-existing regression test does_no_error_on_char_boundary_splitting
was not removed, but was silently rendered ineffective by the new
bytes[0] != b'$' guard, which rejected its input earlier and prevented
it from reaching the buggy slices — leaving CI green through the regression.
Fix
split_hash now rejects any hash string containing non-ASCII bytes up
front. A valid bcrypt hash is always exactly 60 ASCII bytes, so this
closes the entire class of byte-boundary panics rather than guarding each
slice individually.
The fix was merged in PR #103 and released as bcrypt 0.19.2 on 2026-06-20.
Downstream impact
pyca/bcrypt (which depended on bcrypt 0.19.1) is not affected. Its
Python-side wrapper performs its own byte-level salt parsing before
invoking bcrypt::hash_with_salt, and never reaches the buggy code path
in split_hash or verify.
Which versions are affected by RUSTSEC-2026-0199?
1 open source package ship an affected version, including bcrypt.
| Package | Affected | Fixed in |
|---|---|---|
bcrypt crates.io | From 0.19.0 | 0.19.2 |
How do I fix RUSTSEC-2026-0199?
Upgrade bcrypt to 0.19.2 or later.
Upgrade, then put limits on request size, rate and nesting depth so one client cannot exhaust the service. More about Denial of service.
Is RUSTSEC-2026-0199 being exploited?
There is no known exploitation of RUSTSEC-2026-0199 in the wild and no public exploit code.