From c3ae67a2b699fd7697661774c063bcc8dd6cc19a Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Fri, 11 Sep 2026 19:02:25 +0200 Subject: [PATCH] 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) Claude-Session: https://claude.ai/code/session_0186eyzivcTn6wqjEE4Wnxdt --- lib/rails_ext/actiontext_opengraph_embeds.rb | 13 +++++++++---- .../rails_ext/actiontext_opengraph_embeds_test.rb | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/rails_ext/actiontext_opengraph_embeds.rb b/lib/rails_ext/actiontext_opengraph_embeds.rb index 102e1d8..8f283cc 100644 --- a/lib/rails_ext/actiontext_opengraph_embeds.rb +++ b/lib/rails_ext/actiontext_opengraph_embeds.rb @@ -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 diff --git a/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb b/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb index 15c1481..2cb5f5d 100644 --- a/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb +++ b/test/lib/rails_ext/actiontext_opengraph_embeds_test.rb @@ -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"