From 0672673916546ea0ef70a42c2d4ffecbe2495d21 Mon Sep 17 00:00:00 2001 From: "Stanko K.R." Date: Wed, 3 Dec 2025 08:08:34 +0100 Subject: [PATCH] Disallow SSRF via IPv6 addresses mapped to IPv4 addresses --- lib/restricted_http/private_network_guard.rb | 2 +- test/models/opengraph/location_test.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/restricted_http/private_network_guard.rb b/lib/restricted_http/private_network_guard.rb index a9c0c13..0747862 100644 --- a/lib/restricted_http/private_network_guard.rb +++ b/lib/restricted_http/private_network_guard.rb @@ -16,7 +16,7 @@ module RestrictedHTTP def private_ip?(ip) IPAddr.new(ip).then do |ipaddr| - ipaddr.private? || ipaddr.loopback? || ipaddr.link_local? || LOCAL_IP.include?(ipaddr) + ipaddr.private? || ipaddr.loopback? || ipaddr.link_local? || ipaddr.ipv4_mapped? || LOCAL_IP.include?(ipaddr) end rescue IPAddr::InvalidAddressError true diff --git a/test/models/opengraph/location_test.rb b/test/models/opengraph/location_test.rb index b8cb01d..78b3aa2 100644 --- a/test/models/opengraph/location_test.rb +++ b/test/models/opengraph/location_test.rb @@ -29,6 +29,20 @@ class Opengraph::LocationTest < ActiveSupport::TestCase assert_equal [ "is not public" ], location.errors[:url] end + test "IPv6 addresses mapped to IPv4 addresses are blocked" do + Resolv.stubs(:getaddress).with("metadata.internal").returns("::ffff:192.168.1.1") + + location = Opengraph::Location.new("https://metadata.internal") + assert_not location.valid? + assert_equal [ "is not public" ], location.errors[:url] + + Resolv.stubs(:getaddress).with("metadata.internal").returns("::ffff:c0a8:0101") + + location = Opengraph::Location.new("https://metadata.internal") + assert_not location.valid? + assert_equal [ "is not public" ], location.errors[:url] + end + test "avoid reading file urls when expecting HTML" do large_file = Opengraph::Location.new("https://www.example.com/100gb.zip")