CVE-2017-1002201 (Ruby, published 2019-10-15T18:15Z)
Description: value: In haml versions prior to version 5.0.0.beta.2, when using user input to perform tasks on the server, characters like < > " ' must be escaped properly. In this case, the ' character was missed. An attacker can manipulate the input to introduce additional attributes, potentially executing code.
Severity: MEDIUM (CVSS v3 base score: 6.1)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/haml/haml
Files changed:
lib/haml/helpers.rb
test/engine_test.rb
test/pretty_engine_test.rb
test/pretty_results/just_stuff.xhtml
test/results/just_stuff.xhtml
Commit message: Always escape `'` in Haml::Helpers.#html_escape.

In some tests, `attr_wrapper` is changed to be ignored.

I'll split its fix to other commis because not Haml::Helpers but
Haml::AttributeBuilder is responsible for that.


Vulnerable code:
    HTML_ESCAPE_REGEX = /[\"><&]/
    assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
    assert_equal("<p escaped=\"q'uo&#x0022;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
    assert_equal("<div data-foo='Here&#x0027;s a \"quoteful\" string.'></div>\n",
    assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
    assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
    assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
    assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
    assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
    assert_equal("<p escaped=\"q'uo&#x0022;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
    assert_equal("<div data-foo='Here&#x0027;s a \"quoteful\" string.'></div>\n",
    assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
    assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
    assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
    assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
<strong apos="Foo's bar!">Boo!</strong>
<p class='dynamic_quote' dyn='3' quotes="single '"></p>
<strong apos="Foo's bar!">Boo!</strong>
<p class='dynamic_quote' dyn='3' quotes="single '"></p>

Fixed code:
    HTML_ESCAPE_REGEX = /['"><&]/
    assert_equal("<p escaped=\"quo&#039;te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
    assert_equal("<p escaped='q&#039;uo\"te'></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
    assert_equal("<div data-foo='Here&#039;s a \"quoteful\" string.'></div>\n",
    assert_equal(%Q{<a a='foo&#039;bar'>bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
    assert_equal(%Q{<a a='foo&#039;bar'>bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
    assert_equal(%Q{<a a='foo &#039; bar'>bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
    assert_equal(%Q{<a a='foo \\&#039; bar'>bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
    assert_equal("<p escaped=\"quo&#039;te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
    assert_equal("<p escaped='q&#039;uo\"te'></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
    assert_equal("<div data-foo='Here&#039;s a \"quoteful\" string.'></div>\n",
    assert_equal(%Q{<a a='foo&#039;bar'>bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
    assert_equal(%Q{<a a='foo&#039;bar'>bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
    assert_equal(%Q{<a a='foo &#039; bar'>bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
    assert_equal(%Q{<a a='foo \\&#039; bar'>bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
<strong apos='Foo&#039;s bar!'>Boo!</strong>
<p class='dynamic_quote' dyn='3' quotes='single &#039;'></p>
<strong apos='Foo&#039;s bar!'>Boo!</strong>
<p class='dynamic_quote' dyn='3' quotes='single &#039;'></p>