diff --git a/app/assets/javascripts/discourse/lib/markdown.js b/app/assets/javascripts/discourse/lib/markdown.js index cee428cad32..a28496cdbe8 100644 --- a/app/assets/javascripts/discourse/lib/markdown.js +++ b/app/assets/javascripts/discourse/lib/markdown.js @@ -164,6 +164,9 @@ Discourse.Markdown = { urlAllowed: function (uri, effect, ltype, hints) { var url = typeof(uri) === "string" ? uri : uri.toString(); + // escape single quotes + url = url.replace(/'/g, "'"); + // whitelist some iframe only if (hints && hints.XML_TAG === "iframe" && hints.XML_ATTR === "src") { for (var i = 0, length = _validIframes.length; i < length; i++) { diff --git a/test/javascripts/lib/markdown_test.js b/test/javascripts/lib/markdown_test.js index c557b7f23fe..b40e2a7792b 100644 --- a/test/javascripts/lib/markdown_test.js +++ b/test/javascripts/lib/markdown_test.js @@ -401,14 +401,20 @@ test("URLs in BBCode tags", function() { }); test("urlAllowed", function() { + var urlAllowed = Discourse.Markdown.urlAllowed; + var allowed = function(url, msg) { - equal(Discourse.Markdown.urlAllowed(url), url, msg); + equal(urlAllowed(url), url, msg); }; allowed("/foo/bar.html", "allows relative urls"); allowed("http://eviltrout.com/evil/trout", "allows full urls"); allowed("https://eviltrout.com/evil/trout", "allows https urls"); allowed("//eviltrout.com/evil/trout", "allows protocol relative urls"); + + equal(urlAllowed("http://google.com/test'onmouseover=alert('XSS!');//.swf"), + "http://google.com/test'onmouseover=alert('XSS!');//.swf", + "escape single quotes"); }); test("images", function() {