From f8a91f6dc87c4136779ed189c1a88c915410e03b Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 25 May 2026 22:09:15 +0200 Subject: [PATCH 1/3] Add CURLOPT_RESOLVE and safer following of HTTP redirections Related to: * https://github.com/FreshRSS/FreshRSS/pull/8400 Fixes upstream: * https://github.com/simplepie/simplepie/issues/968 Co-authored-by: Inverle --- src/File.php | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/File.php b/src/File.php index 8abbfcf59..481ff7470 100644 --- a/src/File.php +++ b/src/File.php @@ -109,6 +109,22 @@ public function __construct(string $url, int $timeout = 10, int $redirects = 5, $headers = []; } if (!$force_fsockopen && function_exists('curl_exec')) { + $resolve = false; // FreshRSS + if (empty($curl_options[CURLOPT_PROXY] ?? null)) { // FreshRSS + $resolve = $this->get_curl_resolve_info($url); + if ($resolve === null) { + $this->error = 'URL is not allowed to be resolved: ' . \SimplePie\Misc::url_remove_credentials($url); + $this->success = false; + return; + } elseif ($resolve === false) { + $this->error = 'Failed to resolve domain: ' . \SimplePie\Misc::url_remove_credentials($url); + $this->success = false; + return; + } + if (!empty($resolve)) { + $curl_options[CURLOPT_RESOLVE] = $resolve; // Prevent DNS rebinding + } + } $this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_CURL; $fp = self::curlInit($url, $timeout, $headers, $useragent, $curl_options); $responseHeaders = ''; @@ -154,7 +170,8 @@ public function __construct(string $url, int $timeout = 10, int $redirects = 5, if ($parser->parse()) { $this->set_headers($parser->headers); $this->body = $responseBody; - if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && ($locationHeader = $this->get_header_line('location')) !== '' && $this->redirects < $redirects) { + if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && + ($locationHeader = $this->get_header_line('location')) !== '' && ($this->redirects < $redirects || $redirects === -1)) { // FreshRSS: added infinite redirects for -1 $this->redirects++; $location = \SimplePie\Misc::absolutize_url($locationHeader, $url); if ($location === false) { @@ -320,6 +337,16 @@ protected function on_http_response($response, array $curl_options = []): void { } + /** + * Event to allow inheriting classes to control fetching certain URLs. + * @param string $url + * @return array|null|false A value for CURLOPT_RESOLVE as an array, null if a disallowed IP address was found in DNS records, false if the domain failed to resolve + */ + protected function get_curl_resolve_info(string $url): array|null|false + { + return []; + } + public function get_permanent_uri(): string { return (string) $this->permanent_url; @@ -495,6 +522,7 @@ private static function curlInit( foreach ($curl_options as $curl_param => $curl_value) { curl_setopt($fp, $curl_param, $curl_value); } + curl_setopt($fp, CURLOPT_FOLLOWLOCATION, false); // FreshRSS return $fp; } From d3b8517b404a0e8edcfc19b589dc62d55957a332 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 25 May 2026 22:17:05 +0200 Subject: [PATCH 2/3] Compatibility PHP 7.2 --- src/File.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/File.php b/src/File.php index 481ff7470..e6a8d6122 100644 --- a/src/File.php +++ b/src/File.php @@ -342,7 +342,7 @@ protected function on_http_response($response, array $curl_options = []): void * @param string $url * @return array|null|false A value for CURLOPT_RESOLVE as an array, null if a disallowed IP address was found in DNS records, false if the domain failed to resolve */ - protected function get_curl_resolve_info(string $url): array|null|false + protected function get_curl_resolve_info(string $url) { return []; } From f5da7ca42ef3b429af9de1cab2088203e7a8ed4d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 26 May 2026 21:51:52 +0200 Subject: [PATCH 3/3] Comment Co-authored-by: Inverle --- src/File.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/File.php b/src/File.php index e6a8d6122..13a50afdf 100644 --- a/src/File.php +++ b/src/File.php @@ -340,7 +340,7 @@ protected function on_http_response($response, array $curl_options = []): void /** * Event to allow inheriting classes to control fetching certain URLs. * @param string $url - * @return array|null|false A value for CURLOPT_RESOLVE as an array, null if a disallowed IP address was found in DNS records, false if the domain failed to resolve + * @return array|null|false Returns a value for CURLOPT_RESOLVE as an array, null if no allowed IPs were found, false if the domain failed to resolve. */ protected function get_curl_resolve_info(string $url) {