$attribute, 'url' => $value, 'host' => $host, 'ip' => request()->ip(), 'user_id' => auth()->id(), ]); $fail('The :attribute must not point to internal hosts.'); return; } // Resolve hostname to IP and block private/reserved ranges $ip = gethostbyname($host); // gethostbyname returns the original hostname on failure (e.g. unresolvable) if ($ip === $host && ! filter_var($host, FILTER_VALIDATE_IP)) { $fail('The :attribute host could not be resolved.'); return; } if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { Log::warning('External URL resolves to private or reserved IP', [ 'attribute' => $attribute, 'url' => $value, 'host' => $host, 'resolved_ip' => $ip, 'ip' => request()->ip(), 'user_id' => auth()->id(), ]); $fail('The :attribute must not point to a private or reserved IP address.'); return; } } }