VYPR
High severityNVD Advisory· Published Dec 7, 2021· Updated Aug 4, 2024

ReDos vulnerability on guest checkout email validation

CVE-2021-43805

Description

Solidus is a free, open-source ecommerce platform built on Rails. Versions of Solidus prior to 3.1.4, 3.0.4, and 2.11.13 have a denial of service vulnerability that could be exploited during a guest checkout. The regular expression used to validate a guest order's email was subject to exponential backtracking through a fragment like a.a. Versions 3.1.4, 3.0.4, and 2.11.13 have been patched to use a different regular expression. The maintainers added a check for email addresses that are no longer valid that will print information about any affected orders that exist. If a prompt upgrade is not an option, a workaround is available. It is possible to edit the file config/application.rb manually (with code provided by the maintainers in the GitHub Security Advisory) to check email validity.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
solidus_coreRubyGems
< 2.11.132.11.13
solidus_coreRubyGems
>= 3.0.0, < 3.0.43.0.4
solidus_coreRubyGems
>= 3.1.0, < 3.1.43.1.4

Affected products

1

Patches

2
6be174c955fa

Merge pull request from GHSA-qxmr-qxh6-2cc9

https://github.com/solidusio/solidusMarc BusquéDec 7, 2021via ghsa
4 files changed · +61 8
  • core/lib/spree/core/validators/email.rb+1 1 modified
    @@ -12,7 +12,7 @@ module Spree
       #     end
       #
       class EmailValidator < ActiveModel::EachValidator
    -    EMAIL_REGEXP = /\A([^@\.]|[^@\.]([^@\s]*)[^@\.])@([^@\s]+\.)+[^@\s]+\z/
    +    EMAIL_REGEXP = URI::MailTo::EMAIL_REGEXP
     
         def validate_each(record, attribute, value)
           unless EMAIL_REGEXP.match? value
    
  • core/lib/tasks/solidus/check_orders_with_invalid_email.rake+18 0 added
    @@ -0,0 +1,18 @@
    +# frozen_string_literal: true
    +
    +namespace :solidus do
    +  desc 'Prints orders with invalid email (after fix for GHSA-qxmr-qxh6-2cc9)'
    +  task check_orders_with_invalid_email: :environment do
    +    matches = Spree::Order.find_each.reduce([]) do |matches, order|
    +      order.email.nil? || Spree::EmailValidator::EMAIL_REGEXP.match?(order.email) ? matches : matches + [order]
    +    end
    +    if matches.any?
    +      puts 'Email / ID / Number'
    +      puts(matches.map do |order|
    +        "#{order.email} / #{order.id} / #{order.number}"
    +      end.join("\n"))
    +    else
    +      puts 'NO MATCHES'
    +    end
    +  end
    +end
    
  • core/spec/lib/spree/core/validators/email_spec.rb+4 7 modified
    @@ -24,30 +24,27 @@ class Tester
       let(:invalid_emails) {
         [
           'invalid email@email.com',
    -      '.invalid.email@email.com',
    -      'invalid.email.@email.com',
           '@email.com',
    -      '.@email.com',
           'invalidemailemail.com',
           '@invalid.email@email.com',
           'invalid@email@email.com',
           'invalid.email@@email.com'
         ]
       }
     
    -  it 'validates valid email addresses' do
    +  it 'validates valid email addresses', :aggregate_failures do
         tester = Tester.new
         valid_emails.each do |email|
           tester.email_address = email
    -      expect(tester.valid?).to be true
    +      expect(tester.valid?).to be(true), "expected #{email} to be valid"
         end
       end
     
    -  it 'validates invalid email addresses' do
    +  it 'validates invalid email addresses', :aggregate_failures do
         tester = Tester.new
         invalid_emails.each do |email|
           tester.email_address = email
    -      expect(tester.valid?).to be false
    +      expect(tester.valid?).to be(false), "expected #{email} not to be valid"
         end
       end
     end
    
  • core/spec/lib/tasks/solidus/check_orders_with_invalid_email_spec.rb+38 0 added
    @@ -0,0 +1,38 @@
    +# frozen_string_literal: true
    +
    +require 'rails_helper'
    +
    +path = Spree::Core::Engine.root.join('lib/tasks/solidus/check_orders_with_invalid_email.rake')
    +
    +RSpec.describe 'solidus' do
    +  describe 'check_orders_with_invalid_email' do
    +    include_context(
    +      'rake',
    +      task_path: path,
    +      task_name: 'solidus:check_orders_with_invalid_email'
    +    )
    +
    +    it 'includes orders with invalid email' do
    +      order = create(:order)
    +      order.update_column(:email, 'invalid email@email.com')
    +
    +      expect { task.invoke }.to output(/invalid email@email.com \/ #{order.id} \/ #{order.number}\n/).to_stdout
    +    end
    +
    +    it "doesn't include orders with valid email" do
    +      order = create(:order, email: 'valid@email.com')
    +
    +      expect { task.invoke }.not_to output(/valid@email.com/).to_stdout
    +    end
    +
    +    it "doesn't include orders with no email" do
    +      order = create(:order, user: nil, email: nil, number: '123')
    +
    +      expect { task.invoke }.not_to output(/#{order.number}/).to_stdout
    +    end
    +
    +    it "prints message when no matches found" do
    +      expect { task.invoke }.to output(/NO MATCHES/).to_stdout
    +    end
    +  end
    +end
    
9867153e01e3

Merge pull request from GHSA-qxmr-qxh6-2cc9

https://github.com/solidusio/solidusMarc BusquéDec 7, 2021via ghsa
4 files changed · +61 8
  • core/lib/spree/core/validators/email.rb+1 1 modified
    @@ -12,7 +12,7 @@ module Spree
       #     end
       #
       class EmailValidator < ActiveModel::EachValidator
    -    EMAIL_REGEXP = /\A([^@\.]|[^@\.]([^@\s]*)[^@\.])@([^@\s]+\.)+[^@\s]+\z/
    +    EMAIL_REGEXP = URI::MailTo::EMAIL_REGEXP
     
         def validate_each(record, attribute, value)
           unless EMAIL_REGEXP.match? value
    
  • core/lib/tasks/solidus/check_orders_with_invalid_email.rake+18 0 added
    @@ -0,0 +1,18 @@
    +# frozen_string_literal: true
    +
    +namespace :solidus do
    +  desc 'Prints orders with invalid email (after fix for GHSA-qxmr-qxh6-2cc9)'
    +  task check_orders_with_invalid_email: :environment do
    +    matches = Spree::Order.find_each.reduce([]) do |matches, order|
    +      order.email.nil? || Spree::EmailValidator::EMAIL_REGEXP.match?(order.email) ? matches : matches + [order]
    +    end
    +    if matches.any?
    +      puts 'Email / ID / Number'
    +      puts(matches.map do |order|
    +        "#{order.email} / #{order.id} / #{order.number}"
    +      end.join("\n"))
    +    else
    +      puts 'NO MATCHES'
    +    end
    +  end
    +end
    
  • core/spec/lib/spree/core/validators/email_spec.rb+4 7 modified
    @@ -24,30 +24,27 @@ class Tester
       let(:invalid_emails) {
         [
           'invalid email@email.com',
    -      '.invalid.email@email.com',
    -      'invalid.email.@email.com',
           '@email.com',
    -      '.@email.com',
           'invalidemailemail.com',
           '@invalid.email@email.com',
           'invalid@email@email.com',
           'invalid.email@@email.com'
         ]
       }
     
    -  it 'validates valid email addresses' do
    +  it 'validates valid email addresses', :aggregate_failures do
         tester = Tester.new
         valid_emails.each do |email|
           tester.email_address = email
    -      expect(tester.valid?).to be true
    +      expect(tester.valid?).to be(true), "expected #{email} to be valid"
         end
       end
     
    -  it 'validates invalid email addresses' do
    +  it 'validates invalid email addresses', :aggregate_failures do
         tester = Tester.new
         invalid_emails.each do |email|
           tester.email_address = email
    -      expect(tester.valid?).to be false
    +      expect(tester.valid?).to be(false), "expected #{email} not to be valid"
         end
       end
     end
    
  • core/spec/lib/tasks/solidus/check_orders_with_invalid_email_spec.rb+38 0 added
    @@ -0,0 +1,38 @@
    +# frozen_string_literal: true
    +
    +require 'rails_helper'
    +
    +path = Spree::Core::Engine.root.join('lib/tasks/solidus/check_orders_with_invalid_email.rake')
    +
    +RSpec.describe 'solidus' do
    +  describe 'check_orders_with_invalid_email' do
    +    include_context(
    +      'rake',
    +      task_path: path,
    +      task_name: 'solidus:check_orders_with_invalid_email'
    +    )
    +
    +    it 'includes orders with invalid email' do
    +      order = create(:order)
    +      order.update_column(:email, 'invalid email@email.com')
    +
    +      expect { task.invoke }.to output(/invalid email@email.com \/ #{order.id} \/ #{order.number}\n/).to_stdout
    +    end
    +
    +    it "doesn't include orders with valid email" do
    +      order = create(:order, email: 'valid@email.com')
    +
    +      expect { task.invoke }.not_to output(/valid@email.com/).to_stdout
    +    end
    +
    +    it "doesn't include orders with no email" do
    +      order = create(:order, user: nil, email: nil, number: '123')
    +
    +      expect { task.invoke }.not_to output(/#{order.number}/).to_stdout
    +    end
    +
    +    it "prints message when no matches found" do
    +      expect { task.invoke }.to output(/NO MATCHES/).to_stdout
    +    end
    +  end
    +end
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.