Package: release.debian.org Severity: normal Tags: bookworm X-Debbugs-Cc: angular...@packages.debian.org Control: affects -1 + src:angular.js User: release.debian....@packages.debian.org Usertags: pu
[ Reason ] Fix all CVEs except CVE-2022-25869 that need iexplore and is no-dsa [ Impact ] CVEs are still opened [ Tests ] autopkgtest where added for redos. Manual test for XSS. regression testsuite [ Risks ] Low [ Checklist ] [X] *all* changes are documented in the d/changelog [X] I reviewed all changes and I approve them [X] attach debdiff against the package in (old)stable [X] the issue is verified as fixed in unstable [ Changes ] + + * Team upload + * Move to js team umbrella + * Fix CVE-2022-25844 (Closes: #1014779) + A Regular Expression Denial of Service vulnerability (ReDoS) + was found by providing a custom locale rule that makes + it possible to assign the parameter in posPre: ' '.repeat() + of NUMBER_FORMATS.PATTERNS[1].posPre with a very high value + * Fix CVE-2023-26116 (Closes: #1036694) + A Regular Expression Denial of Service (ReDoS) was found + via the angular.copy() utility function due to the usage + of an insecure regular expression. + * Fix CVE-2023-26116 (Closes: #1036694) + A Regular Expression Denial of Service (ReDoS) was found + via the angular.copy() utility function due to the usage + of an insecure regular expression. + * Fix CVE-2023-26117: + A Regular Expression Denial of Service (ReDoS) was found + via the $resource service due to the usage of an insecure + regular expression. + * Fix CVE-2023-26118: + A Regular Expression Denial of Service (ReDoS) was found + via the <input type="url"> element due to the usage of an + insecure regular expression in the input[url] functionality. + Exploiting this vulnerability is possible by a large + carefully-crafted input, which can result in catastrophic + backtracking. + * Fix CVE-2024-8372: (Closes: #1088804) + Improper sanitization of the value of the 'srcset' + attribute in AngularJS allows attackers to bypass + common image source restrictions, which can also + lead to a form of Content Spoofing + * Fix CVE-2024-8373: (Closes: #1088805) + Improper sanitization of the value of the [srcset] + attribute in <source> HTML elements in AngularJS allows + attackers to bypass common image source restrictions, + which can also lead to a form of Content Spoofing + * Fix CVE-2024-21490: + A regular expression used to split + the value of the ng-srcset directive is vulnerable to + super-linear runtime due to backtracking. With large + carefully-crafted input, this can result in catastrophic + backtracking and cause a denial of service. + * Fix CVE-2025-0716: (Closes: #1104485) + Improper sanitization of the value of the 'href' + and 'xlink:href' attributes in '<image>' SVG elements + in AngularJS allows attackers to bypass common image + source restrictions. This can lead to a form of + Content Spoofing . + * Fix CVE-2025-2336: + An improper sanitization vulnerability has been identified + in ngSanitize module, which allows attackers to bypass + common image source restrictions normally + applied to image elements. This bypass can further lead to a form of + Content Spoofing. Similarly, the application's performance and behavior + could be negatively affected by using too large or slow-to-load images. + [ Other info ] Review by kapouer and kanishiro and LTS team
diff -Nru angular.js-1.8.3/debian/changelog angular.js-1.8.3/debian/changelog --- angular.js-1.8.3/debian/changelog 2023-02-12 07:45:48.000000000 +0100 +++ angular.js-1.8.3/debian/changelog 2025-05-11 23:40:38.000000000 +0200 @@ -1,3 +1,60 @@ +angular.js (1.8.3-1+deb12u1) bookworm; urgency=medium + + * Team upload + * Move to js team umbrella + * Fix CVE-2022-25844 (Closes: #1014779) + A Regular Expression Denial of Service vulnerability (ReDoS) + was found by providing a custom locale rule that makes + it possible to assign the parameter in posPre: ' '.repeat() + of NUMBER_FORMATS.PATTERNS[1].posPre with a very high value + * Fix CVE-2023-26116 (Closes: #1036694) + A Regular Expression Denial of Service (ReDoS) was found + via the angular.copy() utility function due to the usage + of an insecure regular expression. + * Fix CVE-2023-26117: + A Regular Expression Denial of Service (ReDoS) was found + via the $resource service due to the usage of an insecure + regular expression. + * Fix CVE-2023-26118: + A Regular Expression Denial of Service (ReDoS) was found + via the <input type="url"> element due to the usage of an + insecure regular expression in the input[url] functionality. + Exploiting this vulnerability is possible by a large + carefully-crafted input, which can result in catastrophic + backtracking. + * Fix CVE-2024-8372: (Closes: #1088804) + Improper sanitization of the value of the 'srcset' + attribute in AngularJS allows attackers to bypass + common image source restrictions, which can also + lead to a form of Content Spoofing + * Fix CVE-2024-8373: (Closes: #1088805) + Improper sanitization of the value of the [srcset] + attribute in <source> HTML elements in AngularJS allows + attackers to bypass common image source restrictions, + which can also lead to a form of Content Spoofing + * Fix CVE-2024-21490: + A regular expression used to split + the value of the ng-srcset directive is vulnerable to + super-linear runtime due to backtracking. With large + carefully-crafted input, this can result in catastrophic + backtracking and cause a denial of service. + * Fix CVE-2025-0716: (Closes: #1104485) + Improper sanitization of the value of the 'href' + and 'xlink:href' attributes in '<image>' SVG elements + in AngularJS allows attackers to bypass common image + source restrictions. This can lead to a form of + Content Spoofing . + * Fix CVE-2025-2336: + An improper sanitization vulnerability has been identified + in ngSanitize module, which allows attackers to bypass + common image source restrictions normally + applied to image elements. This bypass can further lead to a form of + Content Spoofing. Similarly, the application's performance and behavior + could be negatively affected by using too large or slow-to-load images. + + + -- Bastien Roucariès <ro...@debian.org> Sun, 11 May 2025 23:40:38 +0200 + angular.js (1.8.3-1) unstable; urgency=medium * New upstream release. diff -Nru angular.js-1.8.3/debian/control angular.js-1.8.3/debian/control --- angular.js-1.8.3/debian/control 2021-01-12 18:12:31.000000000 +0100 +++ angular.js-1.8.3/debian/control 2025-05-11 23:40:38.000000000 +0200 @@ -1,11 +1,14 @@ Source: angular.js Section: javascript Priority: optional -Maintainer: Laszlo Boszormenyi (GCS) <g...@debian.org> +Maintainer: Debian Javascript Maintainers <pkg-javascript-de...@lists.alioth.debian.org> +Uploaders: Laszlo Boszormenyi (GCS) <g...@debian.org> Build-Depends: debhelper-compat (= 13), gawk, node-smash (>= 0.0.15-2), uglifyjs, libjs-jquery Standards-Version: 4.5.1 Homepage: https://angularjs.org/ Rules-Requires-Root: no +Vcs-Browser: https://salsa.debian.org/js-team/angular.js +Vcs-Git: https://salsa.debian.org/js-team/angular.js.git Package: libjs-angularjs Architecture: all diff -Nru angular.js-1.8.3/debian/patches/CVE-2022-25844.patch angular.js-1.8.3/debian/patches/CVE-2022-25844.patch --- angular.js-1.8.3/debian/patches/CVE-2022-25844.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2022-25844.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,50 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= <ro...@debian.org> +Date: Mon, 12 May 2025 00:34:07 +0200 +Subject: CVE-2022-25844 + +Avoid a redos by avoiding regex + +bug: https://snyk.io/vuln/SNYK-JS-ANGULAR-2772735 +bug-debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1014779 +origin: part, https://github.com/PebblePad/angular.js/commit/ecfd8d3389d1ef813735febf6bf48ff5d970bc51 +author: Alister Stevens <alis...@pebblepad.co.uk> +--- + src/ng/filter/filters.js | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js +index 482b318..d5106e4 100644 +--- a/src/ng/filter/filters.js ++++ b/src/ng/filter/filters.js +@@ -68,14 +68,24 @@ function currencyFilter($locale) { + fractionSize = formats.PATTERNS[1].maxFrac; + } + +- // If the currency symbol is empty, trim whitespace around the symbol +- var currencySymbolRe = !currencySymbol ? /\s*\u00A4\s*/g : /\u00A4/g; +- + // if null or undefined pass it through +- return (amount == null) +- ? amount +- : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). +- replace(currencySymbolRe, currencySymbol); ++ if (amount === null || amount === undefined) { ++ return amount; ++ } ++ ++ const formattedNumber = formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize); ++ // Validate if currency symbol whitespace trimming is required by checking for the currency symbol first. Fixes potential ReDoS vulnerability - https://www.cve.org/CVERecord?id=CVE-2022-25844 ++ if(!formattedNumber.includes("\u00A4")) return formattedNumber; ++ if(currencySymbol) return formattedNumber.replace(/\u00A4/g,currencySymbol); ++ /* here we know we have u00A4 so at least 2 splitted part and currency symbol is empty*/ ++ let splitted = formattedNumber.split("\u00A4"); ++ const splittedend = splitted.length - 1; ++ splitted[0] = splitted[0].trimEnd(); ++ splitted[splittedend] = splitted[splittedend].trimStart(); ++ if(splittedend > 1) { ++ for(let i=1;i < splittedend; i++) splitted[i] = splitted[i].trim(); ++ } ++ return splitted.join(''); + }; + } + diff -Nru angular.js-1.8.3/debian/patches/CVE-2023-26116.patch angular.js-1.8.3/debian/patches/CVE-2023-26116.patch --- angular.js-1.8.3/debian/patches/CVE-2023-26116.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2023-26116.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,25 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= <ro...@debian.org> +Date: Mon, 12 May 2025 00:58:29 +0200 +Subject: CVE-2023-26116 + +Fix the redos by using regex.flags available since 2020 for all browser + +bug: https://security.snyk.io/vuln/SNYK-JS-ANGULAR-3373044 +origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1036694 +--- + src/Angular.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/Angular.js b/src/Angular.js +index 9b11090..79f4a95 100644 +--- a/src/Angular.js ++++ b/src/Angular.js +@@ -999,7 +999,7 @@ function copy(source, destination, maxDepth) { + return new source.constructor(source.valueOf()); + + case '[object RegExp]': +- var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]); ++ var re = new RegExp(source.source, source.flags); + re.lastIndex = source.lastIndex; + return re; + diff -Nru angular.js-1.8.3/debian/patches/CVE-2023-26117.patch angular.js-1.8.3/debian/patches/CVE-2023-26117.patch --- angular.js-1.8.3/debian/patches/CVE-2023-26117.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2023-26117.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,30 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= <ro...@debian.org> +Date: Mon, 12 May 2025 01:19:39 +0200 +Subject: CVE-2023-26117 + +Fix by linear replace a redos + +bug-poc: https://stackblitz.com/edit/angularjs-vulnerability-resource-trailing-slashes-redos?file=index.js +bug: https://security.snyk.io/vuln/SNYK-JS-ANGULAR-3373045 +bug-debian: https://bugs.debian.org/1036694 +--- + src/ngResource/resource.js | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js +index 11bb45b..3249e3e 100644 +--- a/src/ngResource/resource.js ++++ b/src/ngResource/resource.js +@@ -651,7 +651,11 @@ angular.module('ngResource', ['ng']). + + // strip trailing slashes and set the url (unless this behavior is specifically disabled) + if (self.defaults.stripTrailingSlashes) { +- url = url.replace(/\/+$/, '') || '/'; ++ var i = url.length - 1; ++ while (i >= 0 && url[i] == ('/')) { ++ i--; ++ } ++ url = url.slice(0,i + 1) || '/'; + } + + // Collapse `/.` if found in the last URL path segment before the query. diff -Nru angular.js-1.8.3/debian/patches/CVE-2023-26118.patch angular.js-1.8.3/debian/patches/CVE-2023-26118.patch --- angular.js-1.8.3/debian/patches/CVE-2023-26118.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2023-26118.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,40 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= <ro...@debian.org> +Date: Mon, 12 May 2025 22:31:48 +0200 +Subject: CVE-2023-26118 + +Regular Expression Denial of Service (ReDoS) via the <input type="url"> element due to the +usage of an insecure regular expression in the input[url] functionality. + +Exploiting this vulnerability is possible by a large carefully-crafted input, which can result in catastrophic backtracking. + +origin: backport, https://github.com/angular/angular/blob/3c9b8d9de5978dad99d49aa0107a70eddc4d1968/packages/misc/angular-in-memory-web-api/src/interfaces.ts#L135 +bug: https://security.snyk.io/vuln/SNYK-JS-ANGULAR-3373046 +bug-debian: https://bugs.debian.org/1036694 +--- + src/ng/directive/input.js | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js +index 7dfbf16..90f321b 100644 +--- a/src/ng/directive/input.js ++++ b/src/ng/directive/input.js +@@ -11,18 +11,7 @@ + // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231 + var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/; + // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987) +-// Note: We are being more lenient, because browsers are too. +-// 1. Scheme +-// 2. Slashes +-// 3. Username +-// 4. Password +-// 5. Hostname +-// 6. Port +-// 7. Path +-// 8. Query +-// 9. Fragment +-// 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999 +-var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i; ++var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^/:@][^:@]*(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i + // eslint-disable-next-line max-len + var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/; + var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/; diff -Nru angular.js-1.8.3/debian/patches/CVE-2024-21490.patch angular.js-1.8.3/debian/patches/CVE-2024-21490.patch --- angular.js-1.8.3/debian/patches/CVE-2024-21490.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2024-21490.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,75 @@ +From: Chris Rowe <ch...@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(','); + } + + diff -Nru angular.js-1.8.3/debian/patches/CVE-2024-8373.patch angular.js-1.8.3/debian/patches/CVE-2024-8373.patch --- angular.js-1.8.3/debian/patches/CVE-2024-8373.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2024-8373.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,23 @@ +From: Alister Stevens <alis...@pebblepad.co.uk> +Date: Wed, 18 Sep 2024 16:10:46 +0100 +Subject: CVE-2024-8373 + +origin: backport, https://github.com/PebblePad/angular.js/commit/7cb36590cdfb23fc2106868b21eb7a78311eb36d +bug-cve: ttps://www.cve.org/CVERecord?id=CVE-2024-8373 +--- + src/ng/compile.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ng/compile.js b/src/ng/compile.js +index b90318f..8e7cf98 100644 +--- a/src/ng/compile.js ++++ b/src/ng/compile.js +@@ -2235,7 +2235,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { + nodeName = nodeName_(this.$$element); + + // Sanitize img[srcset] values. +- if (nodeName === 'img' && key === 'srcset') { ++ if ((nodeName === 'img' || nodeName === 'source') && key === 'srcset') { + this[key] = value = sanitizeSrcset(value, '$set(\'srcset\', value)'); + } + diff -Nru angular.js-1.8.3/debian/patches/CVE-2025-0716.patch angular.js-1.8.3/debian/patches/CVE-2025-0716.patch --- angular.js-1.8.3/debian/patches/CVE-2025-0716.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2025-0716.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,30 @@ +From: Alister Stevens <alis...@pebblepad.co.uk> +Date: Tue, 6 May 2025 13:40:27 +0100 +Subject: Fix improper sanitisation of href and xlink:href on SVG image + elements + +Fix CVE-2025-0716 + +origin: backport, https://github.com/PebblePad/angular.js/commit/71513129efd044c09e52d47455d73c62ff3287d8 +bug: https://www.herodevs.com/vulnerability-directory/cve-2025-0716?angularjs-nes +bug-poc: https://codepen.io/herodevs/pen/qEWQmpd/a86a0d29310e12c7a3756768e6c7b915 +--- + src/ng/compile.js | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/ng/compile.js b/src/ng/compile.js +index 8e7cf98..c525895 100644 +--- a/src/ng/compile.js ++++ b/src/ng/compile.js +@@ -3807,6 +3807,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { + (nodeName === 'link' && attrNormalizedName === 'href') + ) { + return $sce.RESOURCE_URL; ++ } else if ( ++ // SVG image href can be abused (content spoofing) ++ (nodeName === "image") && (attrNormalizedName === 'href' || attrNormalizedName === 'ngHref') ++ ) { ++ return $sce.MEDIA_URL; + } else if (nodeName === 'a' && (attrNormalizedName === 'href' || + attrNormalizedName === 'ngHref')) { + return $sce.URL; diff -Nru angular.js-1.8.3/debian/patches/CVE-2025-2336.patch angular.js-1.8.3/debian/patches/CVE-2025-2336.patch --- angular.js-1.8.3/debian/patches/CVE-2025-2336.patch 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/CVE-2025-2336.patch 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,47 @@ +From: =?utf-8?q?Bastien_Roucari=C3=A8s?= <ro...@debian.org> +Date: Sat, 7 Jun 2025 22:22:12 +0200 +Subject: CVE-2025-2336 +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +An improper sanitization vulnerability has been identified in AngularJS' ngSanitize module, +which allows attackers to bypass common image source restrictions normally +applied to image elements. This bypass can further lead to a form of +Content Spoofing. Similarly, the application's performance and behavior +could be negatively affected by using too large or slow-to-load images. + +The $sanitize service, which is provided by the angular-sanitize package, +is used for sanitizing HTML strings by stripping all potentially dangerous tokens. +As part of the sanitization, it checks the URLs of images to ensure they +abide by the defined image source rules. This allows improving the security +of an application by setting restrictions on the sources of images +that can be shown. For example, only allowing images from a specific domain. + +However, due to a bug in the $sanitize service, SVG <image> elements +are not correctly detected as images, even when SVG support is enabled. +As a result, the image source restrictions are not applied to the images +that can be shown. This allows bypassing the image source restrictions configured +in the application, which can also lead to a form of Content Spoofing. +Similarly, the application's performance and behavior can be negatively affected +by using too large or slow-to-load images. + +bug: https://www.herodevs.com/vulnerability-directory/cve-2025-2336 +bug-PoC: https://codepen.io/herodevs/pen/bNGYaXx/412a3a4218387479898912f60c269c6c +--- + src/ngSanitize/sanitize.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/ngSanitize/sanitize.js b/src/ngSanitize/sanitize.js +index 34e0e09..64ce508 100644 +--- a/src/ngSanitize/sanitize.js ++++ b/src/ngSanitize/sanitize.js +@@ -598,7 +598,7 @@ function $SanitizeProvider() { + out(tag); + forEach(attrs, function(value, key) { + var lkey = lowercase(key); +- var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); ++ var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background') || (tag === 'image' && (lkey === 'href' || lkey === 'xlink:href')); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); diff -Nru angular.js-1.8.3/debian/patches/series angular.js-1.8.3/debian/patches/series --- angular.js-1.8.3/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/patches/series 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,8 @@ +CVE-2022-25844.patch +CVE-2023-26116.patch +CVE-2023-26117.patch +CVE-2023-26118.patch +CVE-2024-21490.patch +CVE-2024-8373.patch +CVE-2025-0716.patch +CVE-2025-2336.patch diff -Nru angular.js-1.8.3/debian/salsa-ci.yml angular.js-1.8.3/debian/salsa-ci.yml --- angular.js-1.8.3/debian/salsa-ci.yml 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/salsa-ci.yml 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,6 @@ +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml + +variables: + RELEASE: 'sid' + SALSA_CI_COMPONENTS: 'main contrib non-free' diff -Nru angular.js-1.8.3/debian/tests/control angular.js-1.8.3/debian/tests/control --- angular.js-1.8.3/debian/tests/control 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/control 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,14 @@ +Test-Command: timeout 60 /usr/bin/env node debian/tests/CVE-2022-25844-PoC.js +Depends: libjs-angularjs, nodejs, node-jsdom + +Test-Command: timeout 60 /usr/bin/env node debian/tests/CVE-2023-26116-PoC.js +Depends: libjs-angularjs, nodejs, node-jsdom + +Test-Command: timeout 60 /usr/bin/env node debian/tests/CVE-2023-26117-PoC.js +Depends: libjs-angularjs, nodejs, node-jsdom + +Test-Command: timeout 60 /usr/bin/env node debian/tests/CVE-2023-26118-PoC.js +Depends: libjs-angularjs, nodejs, node-jsdom + +Test-Command: timeout 30 /usr/bin/env node debian/tests/CVE-2024-21490-PoC.js +Depends: libjs-angularjs, nodejs, node-jsdom diff -Nru angular.js-1.8.3/debian/tests/CVE-2022-25844-PoC.js angular.js-1.8.3/debian/tests/CVE-2022-25844-PoC.js --- angular.js-1.8.3/debian/tests/CVE-2022-25844-PoC.js 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/CVE-2022-25844-PoC.js 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,52 @@ +const { JSDOM, VirtualConsole } = require('jsdom'); +const fs = require('fs'); + +const angularJS = fs.readFileSync('/usr/share/javascript/angular.js/angular.min.js', 'utf-8'); + +const virtualConsole = new VirtualConsole(); +virtualConsole.sendTo(console); + +const html = ` +<!DOCTYPE html><html><head><script>${angularJS}</script> +<script> + angular.module('app', []) + .controller('AppCtrl', function($locale, $filter) { + const ctrl = this; + + // Malicious input to trigger potential ReDoS + const malicious = ' '.repeat(1e6); + + console.log('Applying potentially malicious pattern...'); + $locale.NUMBER_FORMATS.PATTERNS[1].posPre = malicious; + $locale.NUMBER_FORMATS.CURRENCY_SYM = ''; + + const start = Date.now(); + try { + const formatted = $filter('currency')(100); + const duration = Date.now() - start; + console.log('Duration:', duration, 'ms'); + + if (duration > 2000) { + process.exit(2); + } else { + process.exit(0); + } + } catch (err) { + process.exit(1); + } + }); +</script></head> +<body ng-app="app" ng-controller="AppCtrl as ctrl"></body></html>`; + +const dom = new JSDOM(html, { + runScripts: 'dangerously', + resources: 'usable', + virtualConsole, + pretendToBeVisual: true +}); +dom.window.process = process; + +dom.window.document.addEventListener("DOMContentLoaded", () => { + const angular = dom.window.angular; + angular.bootstrap(dom.window.document, ['app']); +}); diff -Nru angular.js-1.8.3/debian/tests/CVE-2023-26116-PoC.js angular.js-1.8.3/debian/tests/CVE-2023-26116-PoC.js --- angular.js-1.8.3/debian/tests/CVE-2023-26116-PoC.js 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/CVE-2023-26116-PoC.js 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,86 @@ +#!/usr/bin/env node + +const { JSDOM, VirtualConsole } = require("jsdom"); +const fs = require("fs"); + +const angularPath = "/usr/share/javascript/angular.js/angular.min.js"; +const angularResource = "/usr/share/javascript/angular.js/angular-resource.min.js"; +const angularMocks = "/usr/share/javascript/angular.js/angular-mocks.js"; + +const angularJS = fs.readFileSync(angularPath, "utf-8"); +const angularResourceJS = fs.readFileSync(angularResource, "utf-8"); +const angularMocksJS = fs.readFileSync(angularMocks, "utf-8"); + +const html = ` +<!DOCTYPE html> +<html> +<head> + <script>${angularJS}</script> + <script>${angularResourceJS}</script> + <script>${angularMocksJS}</script> + + <script> + class AppCtrl { + regexPattern = null; + duration = '(N/A)'; + + constructor() { + this.setRegexPatternWithCharsPowerOf2Exponent(17); + setTimeout(() => { + console.log("[E] Timeout"); + windows.process.exit(3); + }, 40 * 1000) + this.runTest(); + } + + setRegexPatternWithCharsPowerOf2Exponent(exponent) { + this.regexPattern = 'x'.repeat(2 ** exponent); + } + + runTest() { + // Escape spacial regular expression characters. + const pattern = this.regexPattern.replace(/[-.?*+^$|\\\/(){}[\]]/g, '\\$&'); + const regex = new RegExp(pattern); + + const start = Date.now(); + angular.copy(regex); + const end = Date.now(); + + this.duration = ((end - start) / 1000).toFixed(2); + console.log(\`Query setup time: \${this.duration} sec\`); + if (this.duration > 3) { + console.log("[E] It took too long!"); + window.process.exit(2); + } else { + window.process.exit(0); + } + } + } + + angular + .module('app', []) + .controller('AppCtrl', AppCtrl); + </script> +</head> +<body ng-app="app" ng-controller="AppCtrl as ctrl"> +</body> +</html> +`; + +const virtualConsole = new VirtualConsole(); +virtualConsole.sendTo(console); + +const dom = new JSDOM(html, { + runScripts: "dangerously", + resources: "usable", + virtualConsole +}); +dom.window.process = process; + +dom.window.document.addEventListener("DOMContentLoaded", () => { + const angular = dom.window.angular; + angular.element(dom.window.document).ready(() => { + angular.bootstrap(dom.window.document, ['app']); + }); +}); + diff -Nru angular.js-1.8.3/debian/tests/CVE-2023-26117-PoC.js angular.js-1.8.3/debian/tests/CVE-2023-26117-PoC.js --- angular.js-1.8.3/debian/tests/CVE-2023-26117-PoC.js 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/CVE-2023-26117-PoC.js 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +const { JSDOM, VirtualConsole } = require("jsdom"); +const fs = require("fs"); + +const angularPath = "/usr/share/javascript/angular.js/angular.min.js"; +const angularResource = "/usr/share/javascript/angular.js/angular-resource.min.js"; +const angularMocks = "/usr/share/javascript/angular.js/angular-mocks.js"; + +const angularJS = fs.readFileSync(angularPath, "utf-8"); +const angularResourceJS = fs.readFileSync(angularResource, "utf-8"); +const angularMocksJS = fs.readFileSync(angularMocks, "utf-8"); + +const html = ` +<!DOCTYPE html> +<html> +<head> + <script>${angularJS}</script> + <script>${angularResourceJS}</script> + <script>${angularMocksJS}</script> + + <script> + class AppCtrl { + constructor($resource) { + this.$resource = $resource; + this.urlSuffix = null; + this.duration = '(N/A)'; + this.setUrlSuffixWithSlashesPowerOf2Exponent(17); // 131,078 slashes + this.runTest(); + } + + setUrlSuffixWithSlashesPowerOf2Exponent(exp) { + this.urlSuffix = 'foo' + '/'.repeat(2 ** exp) + 'bar'; + } + + runTest() { + const api = this.$resource( + '/api/test/' + this.urlSuffix, + {}, + { query: { method: 'GET', isArray: false } } + ); + + const start = Date.now(); + const res = api.query(); + const end = Date.now(); + + this.duration = ((end - start) / 1000).toFixed(2); + console.log(\`Query setup time: \${this.duration} sec\`); + if (this.duration > 20) { + console.log("[E] It took too long!"); + window.process.exit(2); + } else { + window.process.exit(0); + } + + // Clean up + res.$cancelRequest(); + } + } + + angular.module('app', ['ngResource', 'ngMockE2E']) + .controller('AppCtrl', ['$resource', AppCtrl]) + .run(['$httpBackend', function($httpBackend) { + $httpBackend.whenGET(/^\\/api\\/test\\/.*$/) + .respond(200, { ok: true }); + }]); + </script> +</head> +<body ng-app="app" ng-controller="AppCtrl as ctrl"> +</body> +</html> +`; + +const virtualConsole = new VirtualConsole(); +virtualConsole.sendTo(console); + +const dom = new JSDOM(html, { + runScripts: "dangerously", + resources: "usable", + virtualConsole +}); +dom.window.process = process; + +dom.window.document.addEventListener("DOMContentLoaded", () => { + const angular = dom.window.angular; + angular.element(dom.window.document).ready(() => { + angular.bootstrap(dom.window.document, ['app']); + }); +}); + diff -Nru angular.js-1.8.3/debian/tests/CVE-2023-26118-PoC.js angular.js-1.8.3/debian/tests/CVE-2023-26118-PoC.js --- angular.js-1.8.3/debian/tests/CVE-2023-26118-PoC.js 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/CVE-2023-26118-PoC.js 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +const { JSDOM, VirtualConsole } = require("jsdom"); +const fs = require("fs"); + +const angularPath = "/usr/share/javascript/angular.js/angular.min.js"; +const angularResource = "/usr/share/javascript/angular.js/angular-resource.min.js"; +const angularMocks = "/usr/share/javascript/angular.js/angular-mocks.js"; + +const angularJS = fs.readFileSync(angularPath, "utf-8"); +const angularResourceJS = fs.readFileSync(angularResource, "utf-8"); +const angularMocksJS = fs.readFileSync(angularMocks, "utf-8"); + +const html = ` +<!DOCTYPE html> +<html> +<head> + <script>${angularJS}</script> + <script>${angularResourceJS}</script> + <script>${angularMocksJS}</script> + + <script> + // Define controllers. + class AppCtrl { + url = null; + urlInput = null; + urlInputController = null; + urlInputValidators = null; + duration = '(N/A)'; + + constructor() { + this.setUrlWithSlashesPowerOf2Exponent(20); + } + + $postLink() { + // Remove the default validators (which include the URL validator) to prevent + // the browser's freezing during entering a value and run validation on demand. + this.urlInputController = this.urlInput.controller('ngModel'); + } + + setUrlWithSlashesPowerOf2Exponent(exponent) { + this.url = 'scheme:'+('/'.repeat(2 ** exponent)); + } + + validateUrl() { + // Temporarily restore the default validators (which include the URL validator) + // and run validation on demand (while measuring the time it takes). + const start = Date.now(); + this.urlInputController.$validate(); + const end = Date.now(); + + //this.urlInputController.$validators = {}; + this.duration = ((end - start) / 1000).toFixed(2); + console.log(\`Query setup time: \${this.duration} sec\`); + if (this.duration > 20) { + console.log("[E] It took too long!"); + window.process.exit(2); + } else { + window.process.exit(0); + } + } + } + + // Define and configure the app. + const app = angular + .module('app', []) + .controller('AppCtrl', AppCtrl); + setTimeout(() => { + angular.element(document.body).scope().$ctrl.setUrlWithSlashesPowerOf2Exponent(20); + angular.element(document.body).scope().$ctrl.validateUrl(); + } , 200); + </script> +</head> +<body ng-app="app" ng-controller="AppCtrl as $ctrl"> +<input type="url" ng-ref="$ctrl.urlInput" ng-model="$ctrl.url" /> +</body> +</html> +`; + +const virtualConsole = new VirtualConsole(); +virtualConsole.sendTo(console); + +const dom = new JSDOM(html, { + runScripts: "dangerously", + resources: "usable", + virtualConsole +}); +dom.window.process = process; + +dom.window.document.addEventListener("DOMContentLoaded", () => { + const angular = dom.window.angular; + angular.element(dom.window.document).ready(() => { + angular.bootstrap(dom.window.document, ['app']); + }); +}); + diff -Nru angular.js-1.8.3/debian/tests/CVE-2024-21490-PoC.js angular.js-1.8.3/debian/tests/CVE-2024-21490-PoC.js --- angular.js-1.8.3/debian/tests/CVE-2024-21490-PoC.js 1970-01-01 01:00:00.000000000 +0100 +++ angular.js-1.8.3/debian/tests/CVE-2024-21490-PoC.js 2025-05-11 23:40:38.000000000 +0200 @@ -0,0 +1,96 @@ +#!/usr/bin/env node + +const { JSDOM } = require("jsdom"); +const fs = require("fs"); + +const angularPath = "/usr/share/javascript/angular.js/angular.min.js"; +const angularResource = "/usr/share/javascript/angular.js/angular-resource.min.js"; +const angularMocks = "/usr/share/javascript/angular.js/angular-mocks.js"; + +const html = `<!DOCTYPE html> +<html> +<head> + <script src="${angularPath}"></script> + <script src="${angularResource}"></script> + <script src="${angularMocks}"></script> + + <script> + class AppCtrl { + static $inject = ['$compile', '$rootScope']; + + ngSrcSet = null; + ngSrcSetCompiledElem = null; + timeoutId = null; + duration = '(N/A)'; + + constructor($compile, $rootScope) { + this.$compile = $compile; + this.$rootScope = $rootScope; + this.setNgSrcSetWithSpacesPowerOf2Exponent(20); + } + + setNgSrcSetWithSpacesPowerOf2Exponent(exponent) { + this.ngSrcSet = 'http://example.com/image.png 2x,'+(' '.repeat(2 ** exponent))+'http://example.com/image.png'; + } + + compileNgSrcSet() { + console.log("compileNgSrcSet called") + clearTimeout(this.timeoutId); + + // Use setTimeout to allow manual $apply calls. + this.timeoutId = setTimeout(() => { + try { + console.dir(this.ngSrcSetCompiledElem) + this.ngSrcSetCompiledElem[0].innerHtml = (new DOMParser().parseFromString('<img ng-srcset='+this.ngSrcSet+'>','text/html')).body.firstChild; + console.log(this.ngSrcSetCompiledElem) + const scope = this.ngSrcSetCompiledElem.scope(); + + const start = Date.now(); + //console.log(th) + this.$compile(this.ngSrcSetCompiledElem)(scope); + this.$rootScope.$apply(); + const end = Date.now(); + + this.duration = ((end - start) / 1000).toFixed(2); + console.log(\`Query setup time: \${this.duration} sec\`); + if (this.duration > 20) { + console.log("[E] It took too long!"); + window.process.exit(2); + } else { + window.process.exit(0); + } + } catch (err) { + console.error(err); + console.log("[E] crashed!"); + window.process.exit(3); + } finally { + this.$rootScope.$apply(); // apply the duration change + } + }); + } + } + // Define and configure the app. + angular.module('app', []).controller('AppCtrl', AppCtrl); + angular.element(document).ready(() => { + angular.bootstrap(document, ['app']); + console.log("angular ready, sending click"); + setTimeout(() => { + document.getElementById("compilebtn").click(); + }, 50); + }); + </script> +</head> +<body ng-app="app" ng-controller="AppCtrl as $ctrl"> + <input class="repro-input" type="url" ng-model="$ctrl.ngSrcSet" /> + <p ng-ref="$ctrl.ngSrcSetCompiledElem"></p> + <button id="compilebtn" ng-click="$ctrl.compileNgSrcSet()">Compile</button> +</body> +</html> +`; +const dom = new JSDOM(html, { + runScripts: "dangerously", + resources: "usable", + pretendToBeVisual: true, + url: `file://${process.cwd()}/debian/build/` +}); +dom.window.process = process;
signature.asc
Description: This is a digitally signed message part.