diff --git a/core/lib/Drupal/Component/Utility/UrlHelper.php b/core/lib/Drupal/Component/Utility/UrlHelper.php
index 9619dcf0703105754d04ad8d84a829822a44e6fd..27dfc945b18f02a7fef696ce43e975011cf6975b 100644
--- a/core/lib/Drupal/Component/Utility/UrlHelper.php
+++ b/core/lib/Drupal/Component/Utility/UrlHelper.php
@@ -187,13 +187,18 @@ public static function parse($url) {
     ];
 
     // External URLs: not using parse_url() here, so we do not have to rebuild
-    // the scheme, host, and path without having any use for it.
-    // The URL is considered external if it contains the '://' delimiter. Since
-    // a URL can also be passed as a query argument, we check if this delimiter
-    // appears in front of the '?' query argument delimiter.
+    // the scheme, host, and path without having any use for it. The URL is
+    // considered external if it contains the '://' delimiter. Since a URL can
+    // also be passed as a query or fragment argument, check if this delimiter
+    // appears in front of the '?' and '#' query/fragment argument delimiters.
     $scheme_delimiter_position = strpos($url, '://');
     $query_delimiter_position = strpos($url, '?');
-    if ($scheme_delimiter_position !== FALSE && ($query_delimiter_position === FALSE || $scheme_delimiter_position < $query_delimiter_position)) {
+    $fragment_delimiter_position = strpos($url, '#');
+    if (
+      $scheme_delimiter_position !== FALSE &&
+      ($query_delimiter_position === FALSE || $scheme_delimiter_position < $query_delimiter_position) &&
+      ($fragment_delimiter_position === FALSE || $scheme_delimiter_position < $fragment_delimiter_position)
+    ) {
       // Split off the fragment, if any.
       if (str_contains($url, '#')) {
         [$url, $options['fragment']] = explode('#', $url, 2);
diff --git a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
index 158e626c821301afe77e48226b5681bd33a93f7d..f22d6ac3118aa8473cb74270ff833b3d3fc0f994 100644
--- a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
@@ -386,6 +386,30 @@ public static function providerTestParse() {
           'fragment' => 'footer',
         ],
       ],
+      'Absolute URL with URL as fragment' => [
+        'http://example.com/my/path#http://example.com',
+        [
+          'fragment' => 'http://example.com',
+          'path' => 'http://example.com/my/path',
+          'query' => [],
+        ],
+      ],
+      'Relative URL with URL as fragment' => [
+        '/my/path#http://example.com',
+        [
+          'fragment' => 'http://example.com',
+          'path' => '/my/path',
+          'query' => [],
+        ],
+      ],
+      'URL as fragment' => [
+        '#http://example.com',
+        [
+          'fragment' => 'http://example.com',
+          'path' => '',
+          'query' => [],
+        ],
+      ],
     ];
   }