Require a host on a link preview's link and image

Ruby parses "https:/rooms/1" as an HTTPS URL with no host, and a browser
resolves it against whatever origin Campfire is served from, so the scheme
check alone still let a message body aim the preview at a path here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt
This commit is contained in:
Rosa Gutierrez
2026-09-11 19:02:25 +02:00
parent 3a501cd32c
commit c3ae67a2b6
2 changed files with 11 additions and 5 deletions
+9 -4
View File
@@ -24,11 +24,16 @@ class ActionText::Attachment::OpengraphEmbed
end
# A link preview points at what we unfurled, which is always an absolute
# http or https URL. Drop anything else the message body asks for, so a
# body written by hand can't aim the preview's link or its image at another
# scheme or at a path on this Campfire.
# http or https URL naming a host. Drop anything else the message body asks
# for, so a body written by hand can't aim the preview's link or its image at
# another scheme or at a path on this Campfire. A URL like "https:/rooms/1"
# needs the host check as well as the scheme one: Ruby parses it as HTTPS,
# and a browser resolves it against whatever origin Campfire is served from.
def web_url(value)
value if value.present? && URI.parse(value).is_a?(URI::HTTP)
return if value.blank?
parsed = URI.parse(value)
value if parsed.is_a?(URI::HTTP) && parsed.host.present?
rescue URI::InvalidURIError
nil
end
@@ -10,7 +10,8 @@ class ActionText::Attachment::OpengraphEmbedTest < ActiveSupport::TestCase
test "drops a link and an image that aren't web URLs" do
[ "javascript:alert(1)", "data:text/html,pwned", "vbscript:msgbox(1)", "//example.com/image.png",
"/rooms/1", "rooms/1", "", "http://exa mple.com/ " ].each do |value|
"/rooms/1", "rooms/1", "", "http://exa mple.com/ ",
"https:/rooms/1", "https:rooms/1", "http:/rooms/1", "https://", "http://:80/rooms/1" ].each do |value|
embed = embed_from href: value, url: value
assert_nil embed.href, "expected #{value.inspect} to be dropped as a link"