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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions