From: Chris Rowe <chris@pebblepad.co.uk>
Date: Tue, 17 Sep 2024 16:49:06 +0100
Subject: CVE-2024-21490 and CVE-2024-8372

Fix ReDoS vulnerability with ng-srcset

Fix also CVE-2024-8372 by sanitizing

origin: backport, https://github.com/PebblePad/angular.js/commit/2111de19f71fa70ed8aa0a0797612718a6f6e867
bug: https://codepen.io/herodevs/full/xxoQRNL/0072e627abe03e9cda373bc75b4c1017
bug-debian: https://bugs.debian.org/1088804
bug-cve: https://www.cve.org/CVERecord?id=CVE-2024-21490
---
 src/ng/compile.js | 46 ++++++++--------------------------------------
 1 file changed, 8 insertions(+), 38 deletions(-)

diff --git a/src/ng/compile.js b/src/ng/compile.js
index e48b5a9..b90318f 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -2086,46 +2086,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
         throw $compileMinErr('srcset', 'Can\'t pass trusted values to `{0}`: "{1}"', invokeType, value.toString());
       }
 
-      // Such values are a bit too complex to handle automatically inside $sce.
-      // Instead, we sanitize each of the URIs individually, which works, even dynamically.
-
-      // It's not possible to work around this using `$sce.trustAsMediaUrl`.
-      // If you want to programmatically set explicitly trusted unsafe URLs, you should use
-      // `$sce.trustAsHtml` on the whole `img` tag and inject it into the DOM using the
-      // `ng-bind-html` directive.
-
-      var result = '';
-
-      // first check if there are spaces because it's not the same pattern
-      var trimmedSrcset = trim(value);
-      //                (   999x   ,|   999w   ,|   ,|,   )
-      var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
-      var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
-
-      // split srcset into tuple of uri and descriptor except for the last item
-      var rawUris = trimmedSrcset.split(pattern);
-
-      // for each tuples
-      var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
-      for (var i = 0; i < nbrUrisWith2parts; i++) {
-        var innerIdx = i * 2;
-        // sanitize the uri
-        result += $sce.getTrustedMediaUrl(trim(rawUris[innerIdx]));
-        // add the descriptor
-        result += ' ' + trim(rawUris[innerIdx + 1]);
+      var srcSetValues = value.split(',')
+      var sanitisedSrcSet = [];
+      for (const srcSetValue of srcSetValues) {
+        const wellTrimmedSrcSetValue = srcSetValue.trim().replace(/\s{2,}/, ' ');
+        const srcSplit = wellTrimmedSrcSetValue.split(' ');
+        const uri = $sce.getTrustedMediaUrl(srcSplit[0]);
+        sanitisedSrcSet.push(`${uri}${srcSplit[1] !== undefined ? " " + srcSplit[1] : ""}`)
       }
 
-      // split the last item into uri and descriptor
-      var lastTuple = trim(rawUris[i * 2]).split(/\s/);
-
-      // sanitize the last uri
-      result += $sce.getTrustedMediaUrl(trim(lastTuple[0]));
-
-      // and add the last descriptor if any
-      if (lastTuple.length === 2) {
-        result += (' ' + trim(lastTuple[1]));
-      }
-      return result;
+      return sanitisedSrcSet.join(',');
     }
 
 
