diff --git a/core/lib/Drupal/Core/Theme/Icon/IconFinder.php b/core/lib/Drupal/Core/Theme/Icon/IconFinder.php
index 045e31a67cb2567884ccada60b4bcee7b195da4b..28a2d6984378c24d7a04fc79b532cd6a3b256061 100644
--- a/core/lib/Drupal/Core/Theme/Icon/IconFinder.php
+++ b/core/lib/Drupal/Core/Theme/Icon/IconFinder.php
@@ -297,7 +297,9 @@ private function processFoundFiles(Finder $finder, string $source, string $path_
     $has_icon_pattern = \str_contains($path_info_filename, self::ICON_ID_PATTERN);
 
     foreach ($finder as $file) {
+      /** @var SplFileInfo $file */
       $file_absolute_path = $file->getPathName();
+      /** @var \Symfony\Component\Finder\SplFileInfo $file */
       $icon_id = $file->getFilenameWithoutExtension();
 
       // If an {icon_id} pattern is used, extract it to be used.
@@ -305,10 +307,19 @@ private function processFoundFiles(Finder $finder, string $source, string $path_
         $icon_id = self::extractIconIdFromFilename($icon_id, $path_info_filename);
       }
 
+      // Source is the url to access the image, based on the absolute path to
+      // handle icons relative to definition or Drupal root.
+      $source = str_replace($this->appRoot, '', $file_absolute_path);
+      // Url generation with `generateString` method rely on `base_path()` that
+      // will add a prefix based on $GLOBALS['base_path'], default `/`.
+      // Remove any left slash to allow to url generation with a custom
+      // base_path.
+      $source = $this->fileUrlGenerator->generateString(ltrim($source, '/'));
+
       // Icon ID is used as index to avoid duplicates.
       $result[$icon_id] = [
         'icon_id' => $icon_id,
-        'source' => $this->fileUrlGenerator->generateString(str_replace($this->appRoot, '', $file_absolute_path)),
+        'source' => $source,
         'absolute_path' => $file_absolute_path,
         'group' => self::extractGroupFromPath($file->getPath(), $group_position),
       ];
diff --git a/core/modules/system/tests/modules/icon_test/icon_test.icons.yml b/core/modules/system/tests/modules/icon_test/icon_test.icons.yml
index 8896eb500e3942dc813ba3a7c8398d6ff9be0a78..0e82b63b9927dac9e9699c63937d12a1442f3289 100644
--- a/core/modules/system/tests/modules/icon_test/icon_test.icons.yml
+++ b/core/modules/system/tests/modules/icon_test/icon_test.icons.yml
@@ -48,6 +48,14 @@ test_path:
       title="{{ title }}"
     >
 
+test_path_relative_root:
+  extractor: path
+  config:
+    sources:
+      - /core/misc/druplicon.png
+  template: >-
+    {{ icon_id }}: <img src="{{ source }}" width="32" height="32">
+
 test_svg:
   enabled: true
   label: Test svg
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconFinderKernelTest.php b/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconFinderKernelTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a9bfb80dfd3a13309485d98e36b48111ec09aec2
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconFinderKernelTest.php
@@ -0,0 +1,144 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\KernelTests\Core\Theme\Icon;
+
+use Drupal\Core\Theme\Icon\IconFinder;
+use Drupal\Core\Theme\Icon\IconFinderInterface;
+use Drupal\KernelTests\KernelTestBase;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Test icon sources path generated urls.
+ *
+ * Test using the service fileUrlGenerator for a real generateString().
+ * It rely on base_path() that we override here to allow tests with custom
+ * values.
+ *
+ * @group icon
+ *
+ * @coversDefaultClass \Drupal\Core\Theme\Icon\IconFinder
+ */
+class IconFinderKernelTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'system',
+  ];
+
+  /**
+   * The IconFinder instance.
+   *
+   * @var \Drupal\Core\Theme\Icon\IconFinderInterface
+   */
+  private IconFinderInterface $iconFinder;
+
+  /**
+   * The App root instance.
+   *
+   * @var string
+   */
+  private string $appRoot;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    /** @var \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator */
+    $fileUrlGenerator = $this->container->get('file_url_generator');
+    $this->appRoot = $this->container->getParameter('app.root');
+
+    $this->iconFinder = new IconFinder(
+      $fileUrlGenerator,
+      $this->createMock(LoggerInterface::class),
+      $this->appRoot,
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tearDown(): void {
+    $GLOBALS['base_path'] = '/';
+    parent::tearDown();
+  }
+
+  /**
+   * Test the IconFinder::_construct method.
+   */
+  public function testConstructor(): void {
+    $this->assertInstanceOf(IconFinder::class, $this->iconFinder);
+  }
+
+  /**
+   * Data provider for ::testGetFilesFromSourcesPath().
+   *
+   * @return array
+   *   The test cases, to minimize test data, result expected is an array with:
+   *   - icon_id: the expected id
+   *   - source: the expected source value, without left base path,
+   *     processed through generateString().
+   */
+  public static function providerGetFilesFromSourcesPath(): array {
+    return [
+      [
+        [
+          // Use real icons for better test, but `/core` are not managed by
+          // icon_test so they could change and make this test fail.
+          '/core/misc/druplicon.png',
+          'icons/flat/foo.png',
+        ],
+        [
+          'druplicon' => 'core/misc/druplicon.png',
+          'foo' => 'core/modules/system/tests/modules/icon_test/icons/flat/foo.png',
+        ],
+        'core/modules/system/tests/modules/icon_test',
+      ],
+    ];
+  }
+
+  /**
+   * Test the IconFinder::getFilesFromSources method with paths.
+   *
+   * @param array<string> $sources
+   *   The list of remote.
+   * @param array<string, string> $expected
+   *   The expected result as icon_id => source.
+   * @param string $relativePath
+   *   The relative path to simulate an icon in the module/theme definition.
+   *
+   * @dataProvider providerGetFilesFromSourcesPath
+   */
+  public function testGetFilesFromSourcesPath(array $sources, array $expected, string $relativePath): void {
+    $base_path_test = ['/', '/foo/', '/foo/bar/'];
+
+    foreach ($base_path_test as $base_path) {
+      // @todo Remove or adapt as part of https://www.drupal.org/node/2529170.
+      $GLOBALS['base_path'] = $base_path;
+
+      $result = $this->iconFinder->getFilesFromSources(
+        $sources,
+        $relativePath,
+      );
+
+      // Prepare result array matching processFoundFiles() to minimize test data.
+      $expected_result = [];
+      foreach ($expected as $key => $expected_value) {
+        $expected_result[$key] = [
+          'icon_id' => $key,
+          'source' => $base_path . $expected_value,
+          'absolute_path' => DRUPAL_ROOT . '/' . $expected_value,
+          'group' => NULL,
+        ];
+      }
+
+      $this->assertEquals($result, $expected_result);
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconPackManagerKernelTest.php b/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconPackManagerKernelTest.php
index 07c6508cb9088466138047039d609bfcc8ab0e49..82073b59411b39830f79e8368dabae8fda7eb5a5 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconPackManagerKernelTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/Icon/IconPackManagerKernelTest.php
@@ -28,7 +28,7 @@ class IconPackManagerKernelTest extends KernelTestBase {
    */
   private const TEST_ICON_FULL_ID = 'test_minimal:foo';
 
-  private const EXPECTED_TOTAL_TEST_ICONS = 30;
+  private const EXPECTED_TOTAL_TEST_ICONS = 31;
 
   /**
    * {@inheritdoc}
@@ -128,6 +128,7 @@ public function testListIconPackOptions(): void {
       'test_no_settings' => 'test_no_settings (1)',
       'test_settings' => 'Test settings (1)',
       'test_url_path' => 'Test url path (2)',
+      'test_path_relative_root' => 'test_path_relative_root (1)',
     ];
     $this->assertEquals($expected, $actual);
 
@@ -140,6 +141,7 @@ public function testListIconPackOptions(): void {
       'test_no_settings' => 'test_no_settings (1)',
       'test_settings' => 'Test settings (1)',
       'test_url_path' => 'Test url path (2)',
+      'test_path_relative_root' => 'test_path_relative_root (1)',
     ];
     $this->assertEquals($expected, $actual);
   }
diff --git a/core/tests/Drupal/Tests/Core/Theme/Icon/IconFinderTest.php b/core/tests/Drupal/Tests/Core/Theme/Icon/IconFinderTest.php
index 02139701a8128d2b7d5ccc3bdb1ba8b2e589f685..ccdecd31ae1d5a9ab41e2222c6a196d4484d8d21 100644
--- a/core/tests/Drupal/Tests/Core/Theme/Icon/IconFinderTest.php
+++ b/core/tests/Drupal/Tests/Core/Theme/Icon/IconFinderTest.php
@@ -18,7 +18,6 @@
 class IconFinderTest extends UnitTestCase {
 
   private const TEST_ICONS_PATH = 'core/modules/system/tests/modules/icon_test';
-  private const TEST_RELATIVE_URL = 'foo/bar';
 
   /**
    * The file url generator instance.
@@ -614,7 +613,7 @@ public function testGetFilesFromSourcesPath(array $sources, array $expected = []
       ->expects($this->any())
       ->method('generateString')
       ->willReturnCallback(function ($uri) {
-        return self::TEST_RELATIVE_URL . $uri;
+        return base_path() . $uri;
       });
 
     $result = $this->iconFinder->getFilesFromSources(
@@ -630,7 +629,7 @@ public function testGetFilesFromSourcesPath(array $sources, array $expected = []
       $group = $expected[$key][2] ?? NULL;
       $expected_result[$icon_id] = [
         'icon_id' => $icon_id,
-        'source' => self::TEST_RELATIVE_URL . '/' . self::TEST_ICONS_PATH . '/' . $filename,
+        'source' => base_path() . self::TEST_ICONS_PATH . '/' . $filename,
         'absolute_path' => DRUPAL_ROOT . '/' . self::TEST_ICONS_PATH . '/' . $filename,
         'group' => $group,
       ];
@@ -852,3 +851,24 @@ public function testGetFileContents(string $uri, bool $expected): void {
   }
 
 }
+
+// @todo Remove as part of https://www.drupal.org/node/2529170.
+namespace Drupal\Core\Theme\Icon;
+
+if (!function_exists('base_path')) {
+
+  function base_path(): string {
+    return '/';
+  }
+
+}
+
+namespace Drupal\Tests\Core\Theme\Icon;
+
+if (!function_exists('base_path')) {
+
+  function base_path(): string {
+    return '/';
+  }
+
+}