CVE-2026-11998: AngularJS SCE Resource URL Bypass Enables XS
Understanding the SCE Logic Flaw and Protecting Your AngularJS Applications from XSS Attacks

A newly disclosed vulnerability in AngularJS, CVE-2026-11998, allows attackers to bypass Strict Contextual Escaping (SCE) protections and load unauthorized resource URLs including scripts from arbitrary external domains or data: URIs potentially leading to Cross-Site Scripting (XSS). If your application uses AngularJS's trustedResourceUrlList() or resourceWhitelistURL() with regular expression matchers, you are likely affected.
Vulnerability Summary
What Is SCE and Why Does It Matter?
AngularJS's Strict Contextual Escaping (SCE) mode is a security feature designed to prevent unsafe values from being used in security-sensitive contexts. Two of its core services $sce and $sceDelegate work together to enforce trust boundaries, especially for resource URLs URLs that will be used to load external content such as <script> sources, <iframe> documents, and similar elements.
To control which URLs are considered safe, developers use the $sceDelegateProvider#trustedResourceUrlList() method to provide a list of matchers. Each matcher can be a string with wildcard support or a regular expression. According to AngularJS documentation, these regular expressions are supposed to be matched against the entire normalized, absolute URL even if the regular expression does not include explicit ^ and $ anchors.
The Flaw: Partial Regular Expression Application
CVE-2026-11998 exposes a logic flaw in how AngularJS applies regular expressions when validating resource URLs. Despite the documented intent to match against the full URL, a bug in the implementation allows certain regular expressions to be only partially applied. This means that a URL that should be blocked by the matcher may instead pass the check.
Consider the following matcher, which is intended to allow only URLs from https://better.com/ and https://good.com/:
/https:\/\/better\.com\/.*|https:\/\/good\.com\/.*/
Due to the flaw, an attacker can craft a URL that partially satisfies this pattern for example, a URL originating from https://evil.com/ and have it pass SCE's trust check. Once a resource URL is considered trusted, the browser will load and execute it, which can lead to arbitrary JavaScript execution in the context of the victim's browser session.
The bypass works in two primary ways:
- Cross-domain script loading: Loading a malicious .js file from an attacker-controlled domain (e.g., https://evil.com/malicious.js).
- data: URI execution: Injecting JavaScript directly via a data: URI that encodes executable script content.
Attack Surface
Any AngularJS application that uses either of the following is potentially vulnerable to this bypass:
- Uses $sceDelegateProvider#trustedResourceUrlList() with one or more regular expression matchers, and
- Renders resource URLs (e.g., via ng-src on a <script> or <iframe>) based on user-influenced or dynamic values
The impact is XSS if an attacker can supply or influence the resource URL value and the regular expression matcher is susceptible to partial matching, malicious scripts can be loaded and executed in users' browsers.
A Concrete Example
*see interactive reproduction
The reproduction scenario below illustrates the problem. An app configures a trusted resource URL matcher and then binds a resource URL to a <script> element's src attribute:
angular.
module('app', []).
config($sceDelegateProvider => {
$sceDelegateProvider.trustedResourceUrlList([
/https:\/\/better\.com\/.*|https:\/\/good\.com\/.*/
]);
}).
run($sce => {
$sce.getTrustedResourceUrl(resourceUrl);
});
<script ng-src="{{ resourceUrl }}"></script>
Despite the matcher's intent to restrict loading to better.com and good.com, the partial regular expression application flaw means a crafted URL from evil.com, or one using a data: URI, can pass getTrustedResourceUrl()'s check and be loaded by the browser.
Proof of Concept
A full reproduction with code similar to the above can be found here:
Who Is Affected?
This vulnerability affects all AngularJS versions from 1.2.0-rc.3 onward. AngularJS reached end-of-life in December 2021, meaning the upstream project will not be releasing any patches. The fixed versions v1.9.12, v1.5.29, and v1.4.17, are available exclusively through AngularJS NES (Never-Ending Support), HeroDevs' long-term support offering for end-of-life AngularJS versions.
If your organization is running AngularJS in production and is not on an NES plan, there is no upstream patch available to you.
Remediation
The recommended fix is to upgrade to one of the patched NES releases:
- AngularJS NES v1.9.12 (compatible with OSS v1.8.x)
- AngularJS NES v1.5.29
- AngularJS NES v1.4.17
These releases correct the regular expression application logic in SCE so that matchers are always evaluated against the complete, normalized URL as documented.
Staying Protected on End-of-Life AngularJS
AngularJS will never receive an official security patch from the Angular team. CVE-2026-11998 is a reminder that security vulnerabilities continue to exist in end-of-life software and that running unpatched, EOL dependencies in production carries real risk. (previous discovery)
HeroDevs' AngularJS Never-Ending Support provides ongoing security patches, CVE fixes, and compatibility updates for organizations that cannot yet complete a full migration to a modern framework. If you're running AngularJS in production, learn more about AngularJS NES and how it can keep your application protected.
Resources
View All Articles


