File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -94,6 +94,13 @@ protected function ensureHostResolvesToPublicIps($host)
9494
9595 protected function assertPublicIp ($ ip )
9696 {
97+ if (filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_IPV6 )) {
98+ $ packed = inet_pton ($ ip );
99+ if ($ packed !== false && substr ($ packed , 0 , 12 ) === "\0\0\0\0\0\0\0\0\0\0\xff\xff" ) {
100+ $ ip = inet_ntop (substr ($ packed , 12 ));
101+ }
102+ }
103+
97104 $ result = filter_var ($ ip , FILTER_VALIDATE_IP , FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE );
98105
99106 if (! $ result ) {
Original file line number Diff line number Diff line change @@ -308,6 +308,38 @@ public function it_blocks_watermark_urls_that_target_non_public_ip_ranges()
308308 $ this ->makeGenerator ()->setParams (['mark ' => 'http://127.0.0.1/watermark.png ' ]);
309309 }
310310
311+ public static function ipv4MappedIpv6Provider ()
312+ {
313+ return [
314+ 'mapped loopback ' => ['::ffff:127.0.0.1 ' ],
315+ 'mapped loopback (hex form) ' => ['::ffff:7f00:1 ' ],
316+ 'mapped RFC1918 ' => ['::ffff:10.0.0.1 ' ],
317+ 'mapped link-local metadata ' => ['::ffff:169.254.169.254 ' ],
318+ ];
319+ }
320+
321+ #[Test]
322+ #[DataProvider('ipv4MappedIpv6Provider ' )]
323+ public function it_blocks_ipv4_mapped_ipv6_addresses_via_dns ($ mappedIp )
324+ {
325+ $ validator = new RemoteUrlValidator (fn ($ host ) => [['ipv6 ' => $ mappedIp ]]);
326+
327+ $ this ->expectException (InvalidRemoteUrlException::class);
328+ $ this ->expectExceptionMessage ('Destination IP is not publicly routable. ' );
329+
330+ $ validator ->validate ('https://attacker.example/foo.jpg ' );
331+ }
332+
333+ #[Test]
334+ public function it_allows_public_ipv6_addresses ()
335+ {
336+ $ validator = new RemoteUrlValidator (fn ($ host ) => [['ipv6 ' => '2606:4700:4700::1111 ' ]]);
337+
338+ $ validator ->validate ('https://example.com/foo.jpg ' );
339+
340+ $ this ->addToAssertionCount (1 );
341+ }
342+
311343 #[Test]
312344 public function the_watermark_disk_is_the_public_directory_by_default ()
313345 {
You can’t perform that action at this time.
0 commit comments