Hi, I've tried to write a patch for the very specific issue in this CVE. The regex used is derived from the one used in redmine (https://github.com/redmine/redmine/blob/master/lib/redcloth3.rb#L818).
Package built with this patch (in pbuilder) and succesfully tested against the PoC in http://co3k.org/blog/redcloth-unfixed-xss-en As a side note, I would not be able to patch redcloth for a more complex issue or anything in the ragel layer. Regards
Description: fix for CVE-2012-6684 Author: Cédric Barboiron <c...@winkie.fr> --- a/lib/redcloth/formatters/html.rb +++ b/lib/redcloth/formatters/html.rb @@ -111,14 +111,17 @@ end def link(opts) - "<a href=\"#{escape_attribute opts[:href]}\"#{pba(opts)}>#{opts[:name]}</a>" + href = escape_uri(escape_attribute(opts[:href])) + "<a href=\"#{href}\"#{pba(opts)}>#{opts[:name]}</a>" end def image(opts) opts.delete(:align) opts[:alt] = opts[:title] - img = "<img src=\"#{escape_attribute opts[:src]}\"#{pba(opts)} alt=\"#{escape_attribute opts[:alt].to_s}\" />" - img = "<a href=\"#{escape_attribute opts[:href]}\">#{img}</a>" if opts[:href] + src = escape_uri(escape_attribute(opts[:src])) + href = escape_uri(escape_attribute(opts[:href])) if opts[:href] + img = "<img src=\"#{src}\"#{pba(opts)} alt=\"#{escape_attribute opts[:alt].to_s}\" />" + img = "<a href=\"#{href}\">#{img}</a>" if href img end @@ -267,6 +270,22 @@ def escape_attribute(text) html_esc(text, :html_escape_attributes) end + + # fix for CVE-2012-6684 + def escape_uri(uri) + # escape only if filter_html is enabled + return uri unless filter_html + + # accept every scheme://* + # allow only mailto:* + # accept all other uri + m = %r{^([a-zA-Z]+):(?!//)}.match uri + return uri unless m && m[1] != 'mailto' + + # unwanted uri (e.g. javascript:*) + # prefix by '#' + '#' << uri + end def after_transform(text) text.chomp! --- a/spec/fixtures/filter_html.yml +++ b/spec/fixtures/filter_html.yml @@ -175,3 +175,18 @@ --- in: /me <3 beer filtered_html: <p>/me <3 beer</p> +--- +name: CVE-2012-6684 +in: |- + ["clickme":javascript:alert(%27XSS%27)] +filtered_html: <p><a href="#javascript:alert(%27XSS%27)">clickme</a></p> +--- +name: legit http link +in: |- + ["clickme":http://example.com] +filtered_html: <p><a href="http://example.com">clickme</a></p> +--- +name: legit mailto link +in: |- + ["clickme":mailto:u...@example.com] +filtered_html: <p><a href="mailto:u...@example.com">clickme</a></p>