diff --git a/lib/modules/manager/dockerfile/extract.ts b/lib/modules/manager/dockerfile/extract.ts
index f27f7461a8f7d69037737865f590510d4274e01e..3eae1cd46dfbd541d313f972fa279c6deda89677 100644
--- a/lib/modules/manager/dockerfile/extract.ts
+++ b/lib/modules/manager/dockerfile/extract.ts
@@ -7,9 +7,6 @@ import * as ubuntuVersioning from '../../versioning/ubuntu';
 import type { PackageDependency, PackageFile } from '../types';
 
 const variableMarker = '$';
-const variableOpen = '${';
-const variableClose = '}';
-const variableDefaultValueSplit = ':-';
 
 export function extractVariables(image: string): Record<string, string> {
   const variables: Record<string, string> = {};
@@ -96,36 +93,26 @@ function processDepForAutoReplace(
 }
 
 export function splitImageParts(currentFrom: string): PackageDependency {
+  let isVariable = false;
+  let cleanedCurrentFrom = currentFrom;
+
   // Check if we have a variable in format of "${VARIABLE:-<image>:<defaultVal>@<digest>}"
   // If so, remove everything except the image, defaultVal and digest.
-  let isVariable = false;
-  let cleanedCurrentFrom: string = currentFrom;
-  if (
-    currentFrom.startsWith(variableOpen) &&
-    currentFrom.endsWith(variableClose)
-  ) {
-    isVariable = true;
+  if (cleanedCurrentFrom?.includes(variableMarker)) {
+    const defaultValueRegex = regEx(/^\${.+?:-"?(?<value>.*?)"?}$/);
+    const defaultValueMatch =
+      defaultValueRegex.exec(cleanedCurrentFrom)?.groups;
+    if (defaultValueMatch?.value) {
+      isVariable = true;
+      cleanedCurrentFrom = defaultValueMatch.value;
+    }
 
-    // If the variable contains exactly one $ and has the default value, we consider it as a valid dependency;
-    // otherwise skip it.
-    if (
-      currentFrom.split('$').length !== 2 ||
-      currentFrom.indexOf(variableDefaultValueSplit) === -1
-    ) {
+    if (cleanedCurrentFrom?.includes(variableMarker)) {
+      // If cleanedCurrentFrom contains a variable, after cleaning, e.g. "$REGISTRY/alpine", we do not support this.
       return {
         skipReason: 'contains-variable',
       };
     }
-
-    cleanedCurrentFrom = currentFrom.substr(
-      variableOpen.length,
-      currentFrom.length - (variableClose.length + 2)
-    );
-    cleanedCurrentFrom = cleanedCurrentFrom.substr(
-      cleanedCurrentFrom.indexOf(variableDefaultValueSplit) +
-        variableDefaultValueSplit.length
-    );
-    cleanedCurrentFrom = cleanedCurrentFrom.replace(regEx(/^"(.*)"$/), '$1');
   }
 
   const [currentDepTag, currentDigest] = cleanedCurrentFrom.split('@');
@@ -142,30 +129,14 @@ export function splitImageParts(currentFrom: string): PackageDependency {
     depName = depTagSplit.join(':');
   }
 
-  if (depName?.includes(variableMarker)) {
-    // If depName contains a variable, after cleaning, e.g. "$REGISTRY/alpine", we do not support this.
-    return {
-      skipReason: 'contains-variable',
-    };
-  }
-
-  if (currentValue?.includes(variableMarker)) {
-    // If tag contains a variable, e.g. "5.0${VERSION_SUFFIX}", we do not support this.
-    return {
-      skipReason: 'contains-variable',
-    };
-  }
+  const dep: PackageDependency = {
+    depName,
+    currentValue,
+    currentDigest,
+  };
 
   if (isVariable) {
-    // If we have the variable and it contains the default value, we need to return
-    // it as a valid dependency.
-
-    const dep: PackageDependency = {
-      depName,
-      currentValue,
-      currentDigest,
-      replaceString: cleanedCurrentFrom,
-    };
+    dep.replaceString = cleanedCurrentFrom;
 
     if (!dep.currentValue) {
       delete dep.currentValue;
@@ -174,15 +145,8 @@ export function splitImageParts(currentFrom: string): PackageDependency {
     if (!dep.currentDigest) {
       delete dep.currentDigest;
     }
-
-    return dep;
   }
 
-  const dep: PackageDependency = {
-    depName,
-    currentValue,
-    currentDigest,
-  };
   return dep;
 }