Why <img> and <b> tags are not escaped by Angular?

Viewed 51

I am using Angular 13 for my development.

Recently I created a simple angular form with a user input field, I tried providing different kinds of inputs, where I saw that providing input as <b>Hack</b><img src="some_url" > was working and is not escaped by angular.

I tried doing the POC on the same and created a live example here, but could find out that using angular's DOM Sanitizer service also these inputs are not being escaped by angular.

For reference,

.ts

import { Component, SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  userName = 'Angular';

  constructor(private domSanitizer: DomSanitizer) {}

  onSave(): void {
    console.log('save clicked api call');
    this.sanitizeUserName();
  }

  sanitizeUserName(): string {
    const domSanitize = this.domSanitizer.sanitize(1, this.userName);
    console.log('sanitized text/html', domSanitize);
    return domSanitize;
  }
}

.html

<form #userForm="ngForm">
  <label>Username: </label>
  <input type="text" [(ngModel)]="userName" name="username" />

  <div>
    <span>View : </span>
    <div [innerHTML]="userName"></div>
  </div>

  <br />
  <br />
  <button type="button" (click)="onSave()">Save</button>
</form>

enter image description here

1 Answers

Angular will automatically sanitize any input that is passed as an attribute, but it will not escape it. The sanitizer removes potentially dangerous elements (like script tags) to prevent some XSS attacks, but leaves most of them intact. If you're curious, you can look at the tests of Angular's HTML sanitization code.

Assuming that the user name is saved on a remote server when the form is sent, you must sanitize and / or escape the values there. Servers should never trust the client to perform some actions, since an attacker can easily bypass them.

In case you have a Node.js backend or want to display the sanitized value in the browser, the sanitize-html package performs a similar task that Angular's DOM sanitizer does, but you get more control over it.

You could also consider putting some more constraints on the user names by only allowing specific patterns. You can use the pattern attribute to specify a regular expression for the input so users aren't even able to input anything that will later be escaped or sanitized by the server.

Related