mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 13:08:40 +08:00
Any AWS account holder can subscribe their own SNS topic to a Discourse instance's /webhooks/aws and publish bounce notifications that AWS will sign legitimately. The forged bounces are processed against arbitrary user emails, bumping bounce_score and eventually triggering email revocation.. This fix adds a new `aws_sns_topic_arn_allowlist` site setting. Also hardens Jobs::ProcessSnsNotification against three issues: - Binds bounces to (message_id, to_address) via find_by, so a legitimately-subscribed SNS publisher can no longer bounce arbitrary recipients we didn't send to. - Skips duplicate notifications (next if email_log.bounced?) — AWS SNS delivers at-least-once. - Uses update! instead of update_columns so EmailLog's existing before_save normalizes the bounce status code. Also add a dashboard problem flags self-hosted admins whose SMTP looks like SES but who haven't set the allowlist yet. https://github.com/discourse/discourse/security/advisories/GHSA-8f9m-v436-wr3x
46 lines
1.6 KiB
Ruby
Vendored
46 lines
1.6 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe Email::Sns do
|
|
describe ".allowed_topic_arn?" do
|
|
let(:topic_arn) { "arn:aws:sns:us-east-1:123456789012:discourse-bounces" }
|
|
let(:other_topic_arn) { "arn:aws:sns:us-east-1:999999999999:attacker-topic" }
|
|
|
|
before { SiteSetting.aws_sns_topic_arn_allowlist = topic_arn }
|
|
|
|
it "returns false for a blank topic arn" do
|
|
expect(described_class.allowed_topic_arn?(nil)).to eq(false)
|
|
expect(described_class.allowed_topic_arn?("")).to eq(false)
|
|
end
|
|
|
|
it "returns false for a topic arn that is not on the allowlist" do
|
|
expect(described_class.allowed_topic_arn?(other_topic_arn)).to eq(false)
|
|
end
|
|
|
|
it "returns true for a topic arn on the allowlist" do
|
|
expect(described_class.allowed_topic_arn?(topic_arn)).to eq(true)
|
|
end
|
|
|
|
it "matches any entry of a pipe-separated allowlist" do
|
|
SiteSetting.aws_sns_topic_arn_allowlist = "#{topic_arn}|#{other_topic_arn}"
|
|
|
|
expect(described_class.allowed_topic_arn?(topic_arn)).to eq(true)
|
|
expect(described_class.allowed_topic_arn?(other_topic_arn)).to eq(true)
|
|
end
|
|
|
|
it "returns false when the allowlist is empty" do
|
|
SiteSetting.aws_sns_topic_arn_allowlist = ""
|
|
|
|
expect(described_class.allowed_topic_arn?(topic_arn)).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe ".authentic?" do
|
|
it "delegates to the AWS SNS message verifier" do
|
|
require "aws-sdk-sns"
|
|
raw = "{}"
|
|
Aws::SNS::MessageVerifier.any_instance.expects(:authentic?).with(raw).returns(true)
|
|
|
|
expect(described_class.authentic?(raw)).to eq(true)
|
|
end
|
|
end
|
|
end
|