summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-25 16:30:16 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-25 16:30:39 +0000
commit8cd42e056bdf3eb178191ba8dba96407897e622f (patch)
tree5052877867a8c85b3887d0a80bbc6acfad00450a
parent2072adf14d8fd5bcca5e9202196b1dd104e795b0 (diff)
downloadgitlab-ce-8cd42e056bdf3eb178191ba8dba96407897e622f.tar.gz
Add latest changes from gitlab-org/security/gitlab@14-6-stable-ee
-rw-r--r--config/initializers/action_mailer_hooks.rb1
-rw-r--r--lib/gitlab/email/hook/validate_addresses_interceptor.rb32
-rw-r--r--spec/lib/gitlab/email/hook/validate_addresses_interceptor_spec.rb52
3 files changed, 85 insertions, 0 deletions
diff --git a/config/initializers/action_mailer_hooks.rb b/config/initializers/action_mailer_hooks.rb
index 46d5e387d9d..fb09ed34bf6 100644
--- a/config/initializers/action_mailer_hooks.rb
+++ b/config/initializers/action_mailer_hooks.rb
@@ -8,6 +8,7 @@ end
ActionMailer::Base.register_interceptors(
::Gitlab::Email::Hook::AdditionalHeadersInterceptor,
::Gitlab::Email::Hook::EmailTemplateInterceptor,
+ ::Gitlab::Email::Hook::ValidateAddressesInterceptor,
::Gitlab::Email::Hook::DeliveryMetricsObserver
)
diff --git a/lib/gitlab/email/hook/validate_addresses_interceptor.rb b/lib/gitlab/email/hook/validate_addresses_interceptor.rb
new file mode 100644
index 00000000000..e63f047e63d
--- /dev/null
+++ b/lib/gitlab/email/hook/validate_addresses_interceptor.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Email
+ module Hook
+ # Check for unsafe characters in the envelope-from and -to addresses.
+ # These are passed directly as arguments to sendmail and are liable to shell injection attacks:
+ # https://github.com/mikel/mail/blob/2.7.1/lib/mail/network/delivery_methods/sendmail.rb#L53-L58
+ class ValidateAddressesInterceptor
+ UNSAFE_CHARACTERS = /(\\|[^[:print:]])/.freeze
+
+ def self.delivering_email(message)
+ addresses = Array(message.smtp_envelope_from) + Array(message.smtp_envelope_to)
+
+ addresses.each do |address|
+ next unless address.match?(UNSAFE_CHARACTERS)
+
+ Gitlab::AuthLogger.info(
+ message: 'Skipping email with unsafe characters in address',
+ address: address,
+ subject: message.subject
+ )
+
+ message.perform_deliveries = false
+
+ break
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/hook/validate_addresses_interceptor_spec.rb b/spec/lib/gitlab/email/hook/validate_addresses_interceptor_spec.rb
new file mode 100644
index 00000000000..a3f0158db40
--- /dev/null
+++ b/spec/lib/gitlab/email/hook/validate_addresses_interceptor_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Email::Hook::ValidateAddressesInterceptor do
+ describe 'UNSAFE_CHARACTERS' do
+ subject { described_class::UNSAFE_CHARACTERS }
+
+ it { is_expected.to match('\\') }
+ it { is_expected.to match("\x00") }
+ it { is_expected.to match("\x01") }
+ it { is_expected.not_to match('') }
+ it { is_expected.not_to match('user@example.com') }
+ it { is_expected.not_to match('foo-123+bar_456@example.com') }
+ end
+
+ describe '.delivering_email' do
+ let(:mail) do
+ ActionMailer::Base.mail(to: 'test@mail.com', from: 'info@mail.com', subject: 'title', body: 'hello')
+ end
+
+ let(:unsafe_email) { "evil+\x01$HOME@example.com" }
+
+ it 'sends emails to normal addresses' do
+ expect(Gitlab::AuthLogger).not_to receive(:info)
+ expect { mail.deliver_now }.to change(ActionMailer::Base.deliveries, :count)
+ end
+
+ [:from, :to, :cc, :bcc].each do |header|
+ it "does not send emails if the #{header.inspect} header contains unsafe characters" do
+ mail[header] = unsafe_email
+
+ expect(Gitlab::AuthLogger).to receive(:info).with(
+ message: 'Skipping email with unsafe characters in address',
+ address: unsafe_email,
+ subject: mail.subject
+ )
+
+ expect { mail.deliver_now }.not_to change(ActionMailer::Base.deliveries, :count)
+ end
+ end
+
+ [:reply_to].each do |header|
+ it "sends emails if the #{header.inspect} header contains unsafe characters" do
+ mail[header] = unsafe_email
+
+ expect(Gitlab::AuthLogger).not_to receive(:info)
+ expect { mail.deliver_now }.to change(ActionMailer::Base.deliveries, :count)
+ end
+ end
+ end
+end