Skip to content

Silent Trimming of Passwords Longer Than 72 Characters #283

@ckalpakoglu

Description

@ckalpakoglu

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

  1. Install the bcrypt gem (gem install bcrypt).
  2. 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
  1. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions