SECURITY: Properly escape user content within <noscript>

This commit is contained in:
David Taylor 2024-01-17 11:30:27 +00:00 committed by Isaac Janzen
parent c3b8216869
commit 9b50de4569
No known key found for this signature in database
GPG Key ID: D75AF9C21FD8EBCD
3 changed files with 62 additions and 7 deletions

View File

@ -738,6 +738,10 @@ module ApplicationHelper
absolute_url
end
def escape_noscript(&block)
raw capture(&block).gsub(%r{<(/\s*noscript)}i, '&lt;\1')
end
def manifest_url
# If you want the `manifest_url` to be different for a specific action,
# in the action set @manifest_url = X. Originally added for chat to add a

View File

@ -99,6 +99,7 @@
<%= render_google_tag_manager_body_code %>
<noscript data-path="<%= request.env['PATH_INFO'] %>">
<%= escape_noscript do %>
<%= render partial: "layouts/noscript_header" %>
<div id="main-outlet" class="wrap" role="main">
@ -108,6 +109,7 @@
</div>
<%= render partial: "layouts/noscript_footer" %>
<% end %>
</noscript>
<%- unless customization_disabled? %>

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
RSpec.describe "escaping of noscript content" do
def noscript_content
# Browsers do not parse the contents of noscript tags - they just look for the next string matching `</noscript>`
# Can't use nokogiri because it parses documents with the 'scripting flag' disabled, and therefore parses html inside noscript tags
noscript_content = response.body.scan(%r{<noscript.*?>(.*?)</noscript>}m).join("\n")
end
it "does not affect normal content" do
post = Fabricate(:post, raw: 'This is a post with an image <img alt="<Look at this!>">')
get post.url
expect(noscript_content).to include('<img alt="<Look at this!>">')
end
it "escapes noscript in attribute" do
post =
Fabricate(
:post,
raw: 'This is a post with an image <img alt="</noscript>"> containing a noscript end tag',
)
get post.url
expect(noscript_content).to include('<img alt="&lt;/noscript>">')
end
it "escapes noscript with trailing whitespace" do
post =
Fabricate(
:post,
raw: 'This is a post with an image <img alt="</noscript >"> containing a noscript end tag',
)
get post.url
expect(noscript_content).to include('<img alt="&lt;/noscript >">')
end
it "escapes noscript with leading whitespace" do
# The spec doesn't accept closing tags with leading whitespace. Browsers follow that, but some other parsers are more relaxed so we escape anyway
post =
Fabricate(
:post,
raw: 'This is a post with an image <img alt="</ noscript>"> containing a noscript end tag',
)
get post.url
expect(noscript_content).to include('<img alt="&lt;/ noscript>">')
end
end