Skip to content

Commit 7596011

Browse files
committed
Merge branch '5.x' into 6.x
# Conflicts: # CHANGELOG.md
2 parents c73f9c9 + 3a0b3a0 commit 7596011

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

src/Imaging/RemoteUrlValidator.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff 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) {

tests/Imaging/ImageGeneratorTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff 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
{

0 commit comments

Comments
 (0)