Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Silent Trimming of Passwords Longer Than 72 Characters #283

Copy link
Copy link
@ckalpakoglu

Description

@ckalpakoglu
Issue body actions

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

umrkt, yeyisan, suphi-kondukto and calvinyj

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

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.