diff --git a/lib/carrierwave/uploader/content_type_whitelist.rb b/lib/carrierwave/uploader/content_type_whitelist.rb index 2d723c5a0..131c6871a 100644 --- a/lib/carrierwave/uploader/content_type_whitelist.rb +++ b/lib/carrierwave/uploader/content_type_whitelist.rb @@ -51,7 +51,7 @@ def check_content_type_whitelist!(new_file) def whitelisted_content_type?(content_type) Array(content_type_allowlist).any? do |item| item = Regexp.quote(item) if item.class != Regexp - content_type =~ /#{item}/ + content_type =~ /\A#{item}/ end end diff --git a/spec/uploader/content_type_whitelist_spec.rb b/spec/uploader/content_type_whitelist_spec.rb index e5b7ebecf..428802465 100644 --- a/spec/uploader/content_type_whitelist_spec.rb +++ b/spec/uploader/content_type_whitelist_spec.rb @@ -76,6 +76,33 @@ expect { uploader.cache!(ruby_file) }.not_to raise_error end end + + context "with a crafted content type" do + before do + allow(bork_file).to receive(:content_type).and_return('text/plain; image/png') + allow(uploader).to receive(:content_type_allowlist).and_return('image/png') + end + + it "does not allow spoofing" do + expect { uploader.cache!(bork_file) }.to raise_error(CarrierWave::IntegrityError) + end + end + + context "when the allowlist contains charset" do + before do + allow(uploader).to receive(:content_type_allowlist).and_return(%r{text/plain;\s*charset=utf-8}) + end + + it "accepts the content with allowed charset" do + allow(bork_file).to receive(:content_type).and_return('text/plain; charset=utf-8') + expect { uploader.cache!(bork_file) }.not_to raise_error + end + + it "rejects the content without charset" do + allow(bork_file).to receive(:content_type).and_return('text/plain') + expect { uploader.cache!(bork_file) }.to raise_error(CarrierWave::IntegrityError) + end + end end context "when there is a whitelist" do