191

I am trying to use Angular with a list of apps, and each one is a link to see an app in more detail (apps/app.id):

<a id="{{app.id}}" href="apps/{{app.id}}" >{{app.name}}</a>

Every time I click on one of these links, Chrome shows the URL as

unsafe:chrome-extension://kpbipnfncdpgejhmdneaagc.../apps/app.id

Where does the unsafe: come from?

georgeawg
  • 48,608
  • 13
  • 72
  • 95
ebi
  • 4,862
  • 6
  • 29
  • 40
  • 1
    Keep in mind that you should use `ng-href` in this case rather than just `href`: https://docs.angularjs.org/api/ng/directive/ngHref – hartz89 Jul 19 '16 at 16:04
  • I just use a controller method `function gotoURL(url) { $window.location.href = url; }` – Todd Hale May 22 '19 at 21:25

6 Answers6

368

You need to explicitly add URL protocols to Angular's whitelist using a regular expression. Only http, https, ftp and mailto are enabled by default. Angular will prefix a non-whitelisted URL with unsafe: when using a protocol such as chrome-extension:.

A good place to whitelist the chrome-extension: protocol would be in your module's config block:

var app = angular.module( 'myApp', [] )
.config( [
    '$compileProvider',
    function( $compileProvider )
    {   
        $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|chrome-extension):/);
        // Angular before v1.2 uses $compileProvider.urlSanitizationWhitelist(...)
    }
]);

The same procedure also applies when you need to use protocols such as file: and tel:.

Please see the AngularJS $compileProvider API documentation for more info.

Bob Fanger
  • 28,949
  • 7
  • 62
  • 78
Philip Bulley
  • 9,014
  • 3
  • 33
  • 46
  • 11
    In Angular 1.2 the method name became `$compileProvider.aHrefSanitizationWhitelist` – Mart Aug 27 '13 at 23:46
  • 6
    Default imgSrcSanitizationWhitelist Angular 1.2-rc2 is `/^\s*(https?|ftp|file):|data:image\//`, to access the local filesystem for a chrome packaged app `|filesystem:chrome-extension:` should be added to the end of the regex. – Henning Sep 19 '13 at 12:08
  • 29
    Note that in Angular 1.2, there are actually two methods -- One for links (aHrefSanitizationWhitelist) and one for images (imgSrcSanitizationWhitelist). This had me stuck for a while. – mdierker Dec 05 '13 at 23:17
  • 1
    For a Chrome Packaged App you'll need to add `|blob:chrome-extension:` to the end. – adam8810 Mar 31 '14 at 01:16
  • Note that this does not work for images, for images look at this other question: http://stackoverflow.com/a/22798336/1277693 – papirrin Aug 22 '14 at 08:50
  • 1
    Note the file protocol is different from the blob protocol: `$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|file|blob|ftp|mailto|chrome-extension):/);` – Arnaud Leyder Jan 09 '15 at 14:31
  • I think the author forgot to escape the `-` character in `chrome-extension`. The regexp should be something like /^\s*(https?|ftp|mailto|chrome\-extension):/ – Vladius Feb 06 '15 at 13:19
  • 1
    @Vladius, afaik the `-` char would only need escaping if it were to appear within a character set `[]`, in which case an unescaped `-` would represent a range. The unescaped `-` should be fine in this scenario. – Philip Bulley Feb 06 '15 at 14:31
58

In case anyone has this problem with images, as well:

app.config(['$compileProvider', function ($compileProvider) {
    $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/);
}]);
Selfish
  • 6,023
  • 4
  • 44
  • 63
R. Salisbury
  • 1,954
  • 16
  • 17
  • I tried using the regular expression for white listing the image screen shots i am capturing with html2canvas , now there is no error that says unsafe:data; but the image is not getting captured. Any idea what regular expression i shall use ? I am capturing a image/png as base64 url. Now the html looks like : instead of the actual base64 url – hakuna Feb 29 '16 at 17:31
6

If you just need for mail, tel and sms use this:

app.config(['$compileProvider', function ($compileProvider) {
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|sms|tel):/);
}]);
FelixSFD
  • 6,052
  • 10
  • 43
  • 117
Ivasyliv
  • 61
  • 1
  • 1
3
<a href="{{applicant.resume}}" download> download resume</a>


var app = angular.module("myApp", []);

    app.config(['$compileProvider', function($compileProvider) {
         $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/);
        $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/);

        }]);
D C
  • 708
  • 1
  • 6
  • 17
2

Google Chrome require its extensions to cooperate with Content Security Policy (CSP).

You need to modify your extension to fulfill the requirements of CSP.

https://developer.chrome.com/extensions/contentSecurityPolicy.html

https://developer.mozilla.org/en-US/docs/Security/CSP

Also, angularJS has ngCsp directive which you need to use.

http://docs.angularjs.org/api/ng.directive:ngCsp

Umur Kontacı
  • 35,403
  • 8
  • 73
  • 96
  • I already have the ngCsp directive for that page ''. This is the CSP from my manifest: `"content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'",` Do I need to change the csp in the manifest? – ebi Mar 26 '13 at 04:16
2

For Angular 2+ you can use DomSanitizer's bypassSecurityTrustResourceUrl method.

import {DomSanitizer} from '@angular/platform-browser';

class ExampleComponent {
    sanitizedURL : SafeResourceUrl;

    constructor(
        private sanitizer: DomSanitizer){
        this.sanitizedURL = this.sanitizer.bypassSecurityTrustResourceUrl(); 
    }
}
Raman
  • 1,221
  • 13
  • 20