-
Notifications
You must be signed in to change notification settings - Fork 284
Open
Description
Description
The bcrypt gem silently trims input strings longer than 72 characters during password hashing, which can lead to unexpected behavior.
Specifically, when a string longer than 72 characters is provided, BCrypt::Password.create truncates the input to 72 characters without warning, allowing different inputs to produce the same hash. This can potentially enable password verification bypasses if an attacker uses a different string that matches the first 72 characters of the original input. (similar behavior has been posted by OKTA: https://trust.okta.com/security-advisories/okta-ad-ldap-delegated-authentication-username/ )
Steps to Reproduce
- Install the bcrypt gem (gem install bcrypt).
- Run the following Ruby script:
require 'bcrypt'
cost = 12
userid = "b91fa9b4-69f1-4779-8d45-73f8653057f3" # 36 characters
username = "my.very.long.username.with.more.characters@kondukto.io" # 47 characters
password = "randomStrongPassword" # 20 characters
input = userid + username + password # Total: 103 characters
begin
my_password = BCrypt::Password.create(input, cost: cost)
puts "Hashed password: #{my_password}"
# Validate the correct password
is_valid = BCrypt::Password.new(my_password) == input
puts "Correct password validation: #{is_valid ? 'Success' : 'Failure'}"
# Validate with a different password
wrong_password = "AAAAAAAAAAAAAAAAAAAA"
bypass_input = userid + username + wrong_password # Also 103 characters
is_valid = BCrypt::Password.new(my_password) == bypass_input
puts "Bypass password validation: #{is_valid ? 'Success' : 'Failure'}"
rescue BCrypt::Errors::InvalidCost, BCrypt::Errors::InvalidSalt => e
puts "Error creating password: #{e.message}"
end
- Observe the output:
└> ruby main.rb
Hashed password 1: $2a$12$nefsa21AluV1BF2EXx6Y4.u6ZV4KT3c1ZWXLIOpWV9KZZ2Y1lGQmO
Password validation: Success
Password validation: Success
Expected Behavior
- The bcrypt gem should either:
- Raise an error when an input string exceeds 72 characters, indicating that the input is too long.
- Explicitly document the 72-character limit and warn about truncation in the gem's documentation.
- The validation of bypass_input (which differs from input after the first 72 characters) should return Failure, as it is a different string.
Actual Behavior
- The bcrypt gem silently trims the input string to 72 characters.
- Both input (103 characters) and bypass_input (103 characters, differing after 72 characters) validate successfully against the same hash, indicating that only the first 72 characters are considered.
- No warning or error is raised about the truncation.
Suggested Fix
- Add a check in BCrypt::Password.create to raise an error (e.g., BCrypt::Errors::InputTooLong) if the input exceeds 72 characters. (this is how other programming languages handles it)
- Alternatively, log a warning when truncation occurs to alert developers.
- Update the gem's documentation to clearly state the 72-character limit and the truncation behavior
Environment
- Ruby version: ruby 3.2.3 (2024-01-18 revision 52bb2ac0a6) [x86_64-linux-gnu]
- bcrypt version: 3.1.13
- Operating System: Ubuntu 24.04.2 LTS
References
umrkt, yeyisan, suphi-kondukto and calvinyj
Metadata
Metadata
Assignees
Labels
No labels