Skip to content

Commit

Permalink
Enforce protocol allowlisting for image and image-set CSS funcs
Browse files Browse the repository at this point in the history
https://drafts.csswg.org/css-images-4/ introduces `url()`-like
functionality in new `image` and `image-set` functions. This commit
adds enforcement of protocol allowlisting for these functions.

Note that `image-set` is already widely supported, whereas `image`
is not yet.
  • Loading branch information
ltk committed Jul 26, 2024
1 parent 2bc3d4a commit 4478fa5
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/sanitize/css.rb
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ def property!(prop)
return nil unless valid_url?(child)
end

if name == 'image-set' || name == 'image'
return nil unless valid_image?(child)
end

combined_value << name
return nil if name == 'expression' || combined_value == 'expression'
end
Expand Down Expand Up @@ -345,4 +349,27 @@ def valid_url?(node)
false
end

# Returns `true` if the given node (which is an `image` or `image-set` function) contains only strings
# using an allowlisted protocol.
def valid_image?(node)
return false unless node[:node] == :function
return false unless node.key?(:name) && ['image', 'image-set'].include?(node[:name].downcase)
return false unless Array === node[:value]

node[:value].each do |token|
return false unless Hash === token

case token[:node]
when :string
if token[:value] =~ Sanitize::REGEX_PROTOCOL
return false unless @config[:protocols].include?($1.downcase)
else
return false unless @config[:protocols].include?(:relative)
end
else
next
end
end
end

end; end
6 changes: 6 additions & 0 deletions test/test_sanitize_css.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
"background: url('ht\\tp://example.com/http.jpg')",
"background: url(https://example.com/https.jpg)",
"background: url('https://example.com/https.jpg')",
"background: image-set('relative.jpg' 1x, 'relative-2x.jpg' 2x)",
"background: image-set('https://example.com/https.jpg' 1x, 'https://example.com/https-2x.jpg' 2x)",
"background: image-set('https://example.com/https.jpg' type('image/jpeg'), 'https://example.com/https.avif' type('image/avif'))",
"background: image('relative.jpg');",
"background: image('https://example.com/https.jpg');",
"background: image(rtl 'https://example.com/https.jpg');"
].each do |css|
_(@default.properties(css)).must_equal ''
_(@relaxed.properties(css)).must_equal css
Expand Down

0 comments on commit 4478fa5

Please sign in to comment.