diff --git a/lib/versioning/docker/index.spec.ts b/lib/versioning/docker/index.spec.ts
index a05882608734d14644fecda487a5fb6e57ddafef..c8d55cd16b8c476754731a37fecc399137adf193 100644
--- a/lib/versioning/docker/index.spec.ts
+++ b/lib/versioning/docker/index.spec.ts
@@ -11,6 +11,24 @@ describe('docker.', () => {
       expect(docker.isValid('3')).toBe('3');
       expect(docker.isValid('foo')).toBeNull();
     });
+    it('it should return null if the version string looks like a git commit hash', () => {
+      [
+        '0a1b2c3',
+        '0a1b2c3d',
+        '0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d',
+      ].forEach((version) => {
+        expect(docker.isValid(version)).toBeNull();
+      });
+      [
+        '0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d0',
+        '0a1b2C3',
+        '0z1b2c3',
+        '0A1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d',
+        '123098140293',
+      ].forEach((version) => {
+        expect(docker.isValid(version)).toBe(version);
+      });
+    });
   });
   describe('getMajor(version)', () => {
     it('should support all versions length', () => {
diff --git a/lib/versioning/docker/index.ts b/lib/versioning/docker/index.ts
index 005e4fad7cc1a2d412ba0b74ebeb1ac814277090..3271a87ad37a88409384a82acffe5b70c228d4dc 100644
--- a/lib/versioning/docker/index.ts
+++ b/lib/versioning/docker/index.ts
@@ -8,13 +8,18 @@ export const urls = [
 ];
 export const supportsRanges = false;
 
-const versionRe = /^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/;
+const versionPattern = /^(?<version>\d+(?:\.\d+)*)(?<prerelease>.*)$/;
+const commitHashPattern = /^[a-f0-9]{7,40}$/;
+const numericPattern = /^[0-9]+$/;
 
 function parse(version: string): generic.GenericVersion {
+  if (commitHashPattern.test(version) && !numericPattern.test(version)) {
+    return null;
+  }
   const versionPieces = version.replace(/^v/, '').split('-');
   const prefix = versionPieces.shift();
   const suffix = versionPieces.join('-');
-  const m = versionRe.exec(prefix);
+  const m = versionPattern.exec(prefix);
   if (!m?.groups) {
     return null;
   }
diff --git a/lib/versioning/docker/readme.md b/lib/versioning/docker/readme.md
index 35eb8194bfee1a653eb22b0f58c309fb91bb1eec..fe982e12660486dafae30622622178f0fae903b1 100644
--- a/lib/versioning/docker/readme.md
+++ b/lib/versioning/docker/readme.md
@@ -13,3 +13,7 @@ It's pretty "wild west" for tagging and not always compliant with semver. Docker
 **Are ranges supported?**
 
 No. Although a tag like `12.15` might seem like it means `12.15.x`, it is a tag of its own and may or may not point to an of the available `12.15.x` tags, including `12.15.0`.
+
+**Are commit hashes supported?**
+
+No. An image tag that looks like a Git commit hash should be ignored by Renovate.
diff --git a/lib/versioning/loose/index.spec.ts b/lib/versioning/loose/index.spec.ts
index 781c5f07933cde5463392a1fbe9c7b35441e3842..a5585f60d0e0d3f2437493136e23df1777239798 100644
--- a/lib/versioning/loose/index.spec.ts
+++ b/lib/versioning/loose/index.spec.ts
@@ -29,6 +29,24 @@ describe('loose.', () => {
         expect(loose.isValid(version)).toBeNull();
       });
     });
+    it('it should return null if the version string looks like a git commit hash', () => {
+      [
+        '0a1b2c3',
+        '0a1b2c3d',
+        '0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d',
+      ].forEach((version) => {
+        expect(loose.isValid(version)).toBeNull();
+      });
+      [
+        '0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d0',
+        '0a1b2C3',
+        '0z1b2c3',
+        '0A1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d',
+        '123098140293',
+      ].forEach((version) => {
+        expect(loose.isValid(version)).toBe(version);
+      });
+    });
   });
   describe('isGreaterThan(version)', () => {
     it('it should compare using release number than suffix', () => {
diff --git a/lib/versioning/loose/index.ts b/lib/versioning/loose/index.ts
index b4d4ae8ab7bddec23ab795b6e62518b611d747bb..6731b8cb8d06a7c3cdea0ded8a37993047ad203e 100644
--- a/lib/versioning/loose/index.ts
+++ b/lib/versioning/loose/index.ts
@@ -6,10 +6,15 @@ export const displayName = 'Loose';
 export const urls = [];
 export const supportsRanges = false;
 
-const pattern = /^v?(\d+(?:\.\d+)*)(.*)$/;
+const versionPattern = /^v?(\d+(?:\.\d+)*)(.*)$/;
+const commitHashPattern = /^[a-f0-9]{7,40}$/;
+const numericPattern = /^[0-9]+$/;
 
 function parse(version: string): any {
-  const matches = pattern.exec(version);
+  if (commitHashPattern.test(version) && !numericPattern.test(version)) {
+    return null;
+  }
+  const matches = versionPattern.exec(version);
   if (!matches) {
     return null;
   }
diff --git a/lib/versioning/loose/readme.md b/lib/versioning/loose/readme.md
index c8620b9a9063291f2193c6ffad7c832d9e5abe7c..785c9f1f1846532d61f4db6a834cd668d70c5d5f 100644
--- a/lib/versioning/loose/readme.md
+++ b/lib/versioning/loose/readme.md
@@ -1 +1 @@
-Renovate's "loose" versioning was created for cases where no strict versioning is in place. It works like semver if semver-compliant versions are supplied, but otherwise is "best effort". Essentially it just does its best to sort versions.
+Renovate's "loose" versioning was created for cases where no strict versioning is in place. It works like semver if semver-compliant versions are supplied, but otherwise is "best effort". Essentially it just does its best to sort versions and ignore versions that are not sortable.