fix(validation): improve private URL handling and error feedback

Reject link-local targets even when allowlisted, link private-target errors to endpoint settings, and tighten persistent-volume table widths.
This commit is contained in:
Andras Bacsai committed 2026-08-14 13:34:00 +02:00
1 parent 857375f69c
commit a257224bb7
8 files changed
+126 -185

No files matched your search

+27 -3
View File
@@ -62,7 +62,7 @@ class SafeWebhookUrl implements ValidationRule
if ($this->isBlockedHostname($hostForDns) && ! $this->isAllowedHostname($hostForDns)) {
$this->logBlockedHost($attribute, $host);
$fail('The :attribute must not point to localhost or internal hosts.');
$fail($this->privateTargetMessage($attribute));
return;
}
@@ -70,7 +70,9 @@ class SafeWebhookUrl implements ValidationRule
if (filter_var($hostForIpCheck, FILTER_VALIDATE_IP)) {
if (! $this->isAllowedIp($hostForIpCheck, $hostForDns)) {
$this->logBlockedIp($attribute, $host, $hostForIpCheck);
$fail('The :attribute must not point to private, reserved, loopback, or link-local addresses.');
$fail($this->isLinkLocalIp($hostForIpCheck)
? 'The :attribute must not point to link-local addresses.'
: $this->privateTargetMessage($attribute));
return;
}
@@ -88,13 +90,22 @@ class SafeWebhookUrl implements ValidationRule
foreach ($resolvedIps as $resolvedIp) {
if (! $this->isAllowedIp($resolvedIp, $hostForDns)) {
$this->logBlockedIp($attribute, $host, $resolvedIp);
$fail('The :attribute must not point to private, reserved, loopback, or link-local addresses.');
$fail($this->isLinkLocalIp($resolvedIp)
? 'The :attribute must not resolve to a link-local address.'
: $this->privateTargetMessage($attribute));
return;
}
}
}
private function privateTargetMessage(string $attribute): string
{
$settingsUrl = route('settings.advanced').'#endpoint-section';
return "The {$attribute} points to a local or private address that is not allowed. Configure allowed internal targets: {$settingsUrl}";
}
/**
* Build HTTP client options that pin the validated host to the resolved IPs.
*
@@ -334,6 +345,10 @@ class SafeWebhookUrl implements ValidationRule
$ip = $embeddedIpv4;
}
if ($this->isLinkLocalIp($ip)) {
return false;
}
if ($this->isPublicIp($ip)) {
return true;
}
@@ -350,6 +365,15 @@ class SafeWebhookUrl implements ValidationRule
return $this->isAllowlistedIp($ip);
}
private function isLinkLocalIp(string $ip): bool
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
return $this->ipv4InCidr($ip, '169.254.0.0/16');
}
return $this->ipInCidr($ip, 'fe80::/10');
}
private function isPublicIp(string $ip): bool
{
$embeddedIpv4 = $this->extractIpv4FromMappedIpv6($ip);