diff --git a/lib/loofah/html5/scrub.rb b/lib/loofah/html5/scrub.rb
index 2c2b53f9..4e2ca648 100644
--- a/lib/loofah/html5/scrub.rb
+++ b/lib/loofah/html5/scrub.rb
@@ -79,7 +79,7 @@ def scrub_css style
style_tree.each do |node|
next unless node[:node] == :property
next if node[:children].any? do |child|
- [:url, :bad_url, :function].include? child[:node]
+ [:url, :bad_url].include?(child[:node]) || (child[:node] == :function && !WhiteList::ALLOWED_CSS_FUNCTIONS.include?(child[:name].downcase))
end
name = node[:name].downcase
if WhiteList::ALLOWED_CSS_PROPERTIES.include?(name) || WhiteList::ALLOWED_SVG_PROPERTIES.include?(name)
diff --git a/lib/loofah/html5/whitelist.rb b/lib/loofah/html5/whitelist.rb
index 0c4cc1a4..69f17aaf 100644
--- a/lib/loofah/html5/whitelist.rb
+++ b/lib/loofah/html5/whitelist.rb
@@ -137,6 +137,8 @@ module WhiteList
purple red right solid silver teal top transparent underline white
yellow]
+ ACCEPTABLE_CSS_FUNCTIONS = Set.new %w[calc]
+
SHORTHAND_CSS_PROPERTIES = Set.new %w[background border margin padding]
ACCEPTABLE_SVG_PROPERTIES = Set.new %w[fill fill-opacity fill-rule stroke
@@ -155,6 +157,7 @@ module WhiteList
ALLOWED_ATTRIBUTES = ACCEPTABLE_ATTRIBUTES + MATHML_ATTRIBUTES + SVG_ATTRIBUTES
ALLOWED_CSS_PROPERTIES = ACCEPTABLE_CSS_PROPERTIES
ALLOWED_CSS_KEYWORDS = ACCEPTABLE_CSS_KEYWORDS
+ ALLOWED_CSS_FUNCTIONS = ACCEPTABLE_CSS_FUNCTIONS
ALLOWED_SVG_PROPERTIES = ACCEPTABLE_SVG_PROPERTIES
ALLOWED_PROTOCOLS = ACCEPTABLE_PROTOCOLS
ALLOWED_URI_DATA_MEDIATYPES = ACCEPTABLE_URI_DATA_MEDIATYPES
diff --git a/test/html5/test_sanitizer.rb b/test/html5/test_sanitizer.rb
index 26b973a2..b15b32c6 100755
--- a/test/html5/test_sanitizer.rb
+++ b/test/html5/test_sanitizer.rb
@@ -275,6 +275,18 @@ def test_css_negative_value_sanitization_shorthand_css_properties
assert_match %r/-0.05em/, sane.inner_html
end
+ def test_css_function_sanitization_leaves_whitelisted_functions
+ html = ""
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
+ assert_match %r/calc\(5%\)/, sane.inner_html
+ end
+
+ def test_css_function_sanitization_strips_style_attributes_with_unsafe_functions
+ html = ""
+ sane = Nokogiri::HTML(Loofah.scrub_fragment(html, :strip).to_html)
+ assert_match %r/<\/span>/, sane.inner_html
+ end
+
def test_issue_90_slow_regex
skip("timing tests are hard to make pass and have little regression-testing value")