Headline
CVE-2023-25172: SECURITY: Prevent XSS in local oneboxes (#20009) · discourse/discourse@1a5a6f6
Discourse is an open-source discussion platform. Prior to version 3.0.1 of the stable
branch and version 3.1.0.beta2 of the beta
and tests-passed
branches, a maliciously crafted URL can be included in a user’s full name field to to carry out cross-site scripting attacks on sites with a disabled or overly permissive CSP (Content Security Policy). Discourse’s default CSP prevents this vulnerability. The vulnerability is patched in version 3.0.1 of the stable
branch and version 3.1.0.beta2 of the beta
and tests-passed
branches. As a workaround, enable and/or restore your site’s CSP to the default one provided with Discourse.
@@ -198,6 +198,66 @@ def preview(url, user = nil, category = nil, topic = nil) “<p><a href=\"#{Discourse.base_url}/new?%27class=black\">http://test.localhost/new?%27class=black</a></p>", ) end
it “escapes URLs of local audio uploads” do result = described_class.onebox_raw( “#{Discourse.base_url}/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’<>", ) expect(result[:onebox]).to eq(<<~HTML) <audio controls> <source src=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E’> <a href=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E’> http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E </a> </audio> HTML expect(result[:preview]).to eq(<<~HTML) <audio controls> <source src=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E’> <a href=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E’> http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.wav#’%3C%3E </a> </audio> HTML end
it “escapes URLs of local video uploads” do result = described_class.onebox_raw( “#{Discourse.base_url}/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’<>", ) expect(result[:onebox]).to eq(<<~HTML) <div class="onebox video-onebox"> <video width="100%” height="100%” controls=""> <source src=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E’> <a href=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E’> http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E </a> </video> </div> HTML expect(result[:preview]).to eq(<<~HTML) <div class="onebox video-onebox"> <video width="100%” height="100%" controls=""> <source src=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E’> <a href=’http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E’> http://test.localhost/uploads/default/original/1X/a1c31803be81b85ecafc4f77b1008eee9b3b82f4.mp4#’%3C%3E </a> </video> </div> HTML end
it “escapes URLs of generic local links” do result = described_class.onebox_raw(“#{Discourse.base_url}/g/somegroup#’onerror=’”) expect(result[:onebox]).to eq( "<a href=’http://test.localhost/g/somegroup#’onerror=’’>http://test.localhost/g/somegroup#’onerror=’</a>", ) expect(result[:preview]).to eq( "<a href=’http://test.localhost/g/somegroup#’onerror=’’>http://test.localhost/g/somegroup#’onerror=’</a>", ) end end
describe “.external_onebox” do