diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index c8eb2d5793646783d468afad684516ef4148a641..cc5194f6786fcaaa2985179b8522fd4ca1ffb6f9 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1756,6 +1756,21 @@ Here's an example of where you use this to group together all packages from the
 }
 ```
 
+### matchSourceUrls
+
+Here's an example of where you use this to match exact package urls:
+
+```json
+{
+  "packageRules": [
+    {
+      "matchSourceUrls": ["https://github.com/facebook/react"],
+      "groupName": "React"
+    }
+  ]
+}
+```
+
 ### matchUpdateTypes
 
 Use this field to match rules against types of updates.
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index cdbb0ae6d4a62b408f334fad19a2a92fcc1ce735..a28240c12eea6e4650064bfac0223e9201843c0e 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -1022,6 +1022,18 @@ const options: RenovateOptions[] = [
     cli: false,
     env: false,
   },
+  {
+    name: 'matchSourceUrls',
+    description: 'A list of source URLs to exact match against.',
+    type: 'array',
+    subType: 'string',
+    allowString: true,
+    stage: 'package',
+    parent: 'packageRules',
+    mergeable: true,
+    cli: false,
+    env: false,
+  },
   {
     name: 'replacementName',
     description:
diff --git a/lib/config/types.ts b/lib/config/types.ts
index 3bf10bab7ef118466424d39769aa3c38e59608a6..8c5a068ac3a6539c9ff31e5444bdef37042474a6 100644
--- a/lib/config/types.ts
+++ b/lib/config/types.ts
@@ -274,6 +274,7 @@ export interface PackageRule
   excludePackagePrefixes?: string[];
   matchCurrentVersion?: string | Range;
   matchSourceUrlPrefixes?: string[];
+  matchSourceUrls?: string[];
   matchUpdateTypes?: UpdateType[];
 }
 
diff --git a/lib/config/validation.ts b/lib/config/validation.ts
index 40e40ab33f65650db00a0ff3befa908fbf61e91d..383790945cb8ac05ffa68454b8e9a75ec69b0444 100644
--- a/lib/config/validation.ts
+++ b/lib/config/validation.ts
@@ -304,6 +304,7 @@ export async function validateConfig(
               'excludePackagePrefixes',
               'matchCurrentVersion',
               'matchSourceUrlPrefixes',
+              'matchSourceUrls',
               'matchUpdateTypes',
             ];
             if (key === 'packageRules') {
diff --git a/lib/util/package-rules.spec.ts b/lib/util/package-rules.spec.ts
index 30816b299aa75e44d50b208bf1525c03fe92ff17..ffb02321bff85f53b77ee5eb81b81ea12183423a 100644
--- a/lib/util/package-rules.spec.ts
+++ b/lib/util/package-rules.spec.ts
@@ -495,6 +495,68 @@ describe('util/package-rules', () => {
     const res = applyPackageRules({ ...config, ...dep });
     expect(res.x).toBeUndefined();
   });
+  it('matches matchSourceUrls', () => {
+    const config: TestConfig = {
+      packageRules: [
+        {
+          matchSourceUrls: [
+            'https://github.com/foo/bar',
+            'https://github.com/renovatebot/presets',
+          ],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      depName: 'a',
+      updateType: 'patch' as UpdateType,
+      sourceUrl: 'https://github.com/renovatebot/presets',
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBe(1);
+  });
+  it('non-matches matchSourceUrls', () => {
+    const config: TestConfig = {
+      packageRules: [
+        {
+          matchSourceUrls: [
+            'https://github.com/foo/bar',
+            'https://github.com/facebook/react',
+          ],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      depName: 'a',
+      updateType: 'patch' as UpdateType,
+      sourceUrl: 'https://github.com/facebook/react-native',
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBeUndefined();
+  });
+  it('handles matchSourceUrls when missing sourceUrl', () => {
+    const config: TestConfig = {
+      packageRules: [
+        {
+          matchSourceUrls: [
+            'https://github.com/foo/bar',
+            'https://github.com/renovatebot/',
+          ],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      depName: 'a',
+      updateType: 'patch' as UpdateType,
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBeUndefined();
+  });
   it('filters naked depType', () => {
     const config: TestConfig = {
       packageRules: [
@@ -791,4 +853,25 @@ describe('util/package-rules', () => {
     const res = applyPackageRules({ ...config, ...dep });
     expect(res.x).toBe(1);
   });
+  it('matches matchSourceUrls(case-insensitive)', () => {
+    const config: TestConfig = {
+      packageRules: [
+        {
+          matchSourceUrls: [
+            'https://github.com/foo/bar',
+            'https://github.com/Renovatebot/renovate',
+          ],
+          x: 1,
+        },
+      ],
+    };
+    const dep = {
+      depType: 'dependencies',
+      depName: 'a',
+      updateType: 'patch' as UpdateType,
+      sourceUrl: 'https://github.com/renovatebot/Renovate',
+    };
+    const res = applyPackageRules({ ...config, ...dep });
+    expect(res.x).toBe(1);
+  });
 });
diff --git a/lib/util/package-rules.ts b/lib/util/package-rules.ts
index 46a62b37cde52afe4a100b0ca9d309dd2b55524d..ec18e0f909ddcd078f670097f42470d1e48a6a1d 100644
--- a/lib/util/package-rules.ts
+++ b/lib/util/package-rules.ts
@@ -45,6 +45,7 @@ function matchesRule(
   const excludePackagePatterns = packageRule.excludePackagePatterns || [];
   const excludePackagePrefixes = packageRule.excludePackagePrefixes || [];
   const matchSourceUrlPrefixes = packageRule.matchSourceUrlPrefixes || [];
+  const matchSourceUrls = packageRule.matchSourceUrls || [];
   const matchCurrentVersion = packageRule.matchCurrentVersion || null;
   const matchUpdateTypes = packageRule.matchUpdateTypes || [];
   let positiveMatch = false;
@@ -210,6 +211,16 @@ function matchesRule(
     }
     positiveMatch = true;
   }
+  if (matchSourceUrls.length) {
+    const upperCaseSourceUrl = sourceUrl?.toUpperCase();
+    const isMatch = matchSourceUrls.some(
+      (url) => upperCaseSourceUrl === url.toUpperCase()
+    );
+    if (!isMatch) {
+      return false;
+    }
+    positiveMatch = true;
+  }
   if (matchCurrentVersion) {
     const version = allVersioning.get(versioning);
     const matchCurrentVersionStr = matchCurrentVersion.toString();