CVE-2022-3741 (Ruby, published 2022-10-28T13:15Z)
Description: value: Impact varies for each individual vulnerability in the application. For generation of accounts, it may be possible, depending on the amount of system resources available, to create a DoS event in the server. These accounts still need to be activated; however, it is possible to identify the output Status Code to separate accounts that are generated and waiting for email verification. \n\nFor the sign in directories, it is possible to brute force login attempts to either login portal, which could lead to account compromise.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-307 \u2014 Improper Restriction of Excessive Authentication Attempts
The product does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame, making it more susceptible to brute force attacks.
Repository: https://github.com/chatwoot/chatwoot
Files changed:
config/initializers/rack_attack.rb
Commit message: chore: Improve rack-attack configuration (#5389)

fixes: https://github.com/chatwoot/product/issues/540

Vulnerable code:
  ### Prevent Brute-Force Login Attacks ###
  throttle('login/ip', limit: 5, period: 20.seconds) do |req|
    req.ip if req.path == '/auth/sign_in' && req.post?
  end

  ## Prevent Brute-Force Signup Attacks ###
  throttle('accounts/ip', limit: 5, period: 5.minutes) do |req|
    req.ip if req.path == '/api/v1/accounts' && req.post?
  end

  ## Prevent Conversation Bombing on Widget APIs ###
  throttle('api/v1/widget/conversations', limit: 6, period: 12.hours) do |req|
    req.ip if req.path == '/api/v1/widget/conversations' && req.post?
  ## Prevent Contact update Bombing in Widget API ###
  throttle('api/v1/widget/contacts', limit: 60, period: 1.hour) do |req|
    req.ip if req.path == '/api/v1/widget/contacts' && (req.patch? || req.put?)
  end

  # ref: https://github.com/rack/rack-attack/issues/399
  throttle('login/email', limit: 20, period: 5.minutes) do |req|
    if req.path == '/auth/sign_in' && req.post?
  throttle('super_admin_login/email', limit: 20, period: 5.minutes) do |req|
    if req.path == '/super_admin/sign_in' && req.post?
    if req.path == '/auth/password' && req.post?

Fixed code:

    # Rails would allow requests to paths with extentions, so lets compare against the path with extention stripped
    # example /auth & /auth.json would both work
    def path_without_extentions
      path[/^[^.]+/]
    end
  ### Prevent Brute-Force Super Admin Login Attacks ###
  throttle('super_admin_login/ip', limit: 5, period: 5.minutes) do |req|
    req.ip if req.path_without_extentions == '/super_admin/sign_in' && req.post?
  throttle('super_admin_login/email', limit: 5, period: 15.minutes) do |req|
    if req.path_without_extentions == '/super_admin/sign_in' && req.post?
      # ref: https://github.com/rack/rack-attack/issues/399
  # ### Prevent Brute-Force Login Attacks ###
  throttle('login/ip', limit: 5, period: 5.minutes) do |req|
    req.ip if req.path_without_extentions == '/auth/sign_in' && req.post?
  end

  throttle('login/email', limit: 10, period: 15.minutes) do |req|
    if req.path_without_extentions == '/auth/sign_in' && req.post?
      # ref: https://github.com/rack/rack-attack/issues/399
  ## Reset password throttling
  throttle('reset_password/ip', limit: 5, period: 30.minutes) do |req|
    req.ip if req.path_without_extentions == '/auth/password' && req.post?
  end

    if req.path_without_extentions == '/auth/password' && req.post?

  ## Prevent Brute-Force Signup Attacks ###
  throttle('accounts/ip', limit: 5, period: 30.minutes) do |req|
    req.ip if req.path_without_extentions == '/api/v1/accounts' && req.post?
  end

  ## Prevent Conversation Bombing on Widget APIs ###
  throttle('api/v1/widget/conversations', limit: 6, period: 12.hours) do |req|
    req.ip if req.path_without_extentions == '/api/v1/widget/conversations' && req.post?
  end

  ## Prevent Contact update Bombing in Widget API ###
  throttle('api/v1/widget/contacts', limit: 60, period: 1.hour) do |req|
    req.ip if req.path_without_extentions == '/api/v1/widget/contacts' && (req.patch? || req.put?)
  end