diff --git a/services/web/app/views/project/editor/chat.pug b/services/web/app/views/project/editor/chat.pug index cdfbcfc097..a560f81724 100644 --- a/services/web/app/views/project/editor/chat.pug +++ b/services/web/app/views/project/editor/chat.pug @@ -43,7 +43,7 @@ aside.chat( mathjax, ng-repeat="content in message.contents track by $index" ) - span(ng-bind-html="content | linky:'_blank'") + span(ng-bind-html="content | linky:'_blank':{rel: 'noreferrer noopener'}") .new-message textarea( diff --git a/services/web/app/views/project/editor/review-panel.pug b/services/web/app/views/project/editor/review-panel.pug index 17c17f90b5..635ba78678 100644 --- a/services/web/app/views/project/editor/review-panel.pug +++ b/services/web/app/views/project/editor/review-panel.pug @@ -357,7 +357,7 @@ script(type='text/ng-template', id='commentEntryTemplate') span.rp-entry-user( style="color: hsl({{ comment.user.hue }}, 70%, 40%);", ) {{ comment.user.name }}: - span(ng-bind-html="comment.content | linky:'_blank'") + span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}") textarea.rp-comment-input( expandable-text-area ng-if="comment.editing" @@ -428,7 +428,7 @@ script(type='text/ng-template', id='resolvedCommentEntryTemplate') style="color: hsl({{ comment.user.hue }}, 70%, 40%);" ng-if="$first || comment.user.id !== thread.messages[$index - 1].user.id" ) {{ comment.user.name }}: - span(ng-bind-html="comment.content | linky:'_blank'") + span(ng-bind-html="comment.content | linky:'_blank':{rel: 'noreferrer noopener'}") .rp-entry-metadata | {{ comment.timestamp | date : 'MMM d, y h:mm a' }} .rp-comment.rp-comment-resolver diff --git a/services/web/public/js/libs/angular-sanitize-1.6.4.js b/services/web/public/js/libs/angular-sanitize-1.6.4.js new file mode 100644 index 0000000000..1d60fdb9db --- /dev/null +++ b/services/web/public/js/libs/angular-sanitize-1.6.4.js @@ -0,0 +1,756 @@ +/** + * @license AngularJS v1.6.4 + * (c) 2010-2017 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular) {'use strict'; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Any commits to this file should be reviewed with security in mind. * + * Changes to this file can potentially create security vulnerabilities. * + * An approval from 2 Core members with history of modifying * + * this file is required. * + * * + * Does the change somehow allow for arbitrary javascript to be executed? * + * Or allows for someone to change the prototype of built-in objects? * + * Or gives undesired access to variables likes document or window? * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +var $sanitizeMinErr = angular.$$minErr('$sanitize'); +var bind; +var extend; +var forEach; +var isDefined; +var lowercase; +var noop; +var nodeContains; +var htmlParser; +var htmlSanitizeWriter; + +/** + * @ngdoc module + * @name ngSanitize + * @description + * + * # ngSanitize + * + * The `ngSanitize` module provides functionality to sanitize HTML. + * + * + *
+ * + * See {@link ngSanitize.$sanitize `$sanitize`} for usage. + */ + +/** + * @ngdoc service + * @name $sanitize + * @kind function + * + * @description + * Sanitizes an html string by stripping all potentially dangerous tokens. + * + * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are + * then serialized back to properly escaped html string. This means that no unsafe input can make + * it into the returned string. + * + * The whitelist for URL sanitization of attribute values is configured using the functions + * `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider + * `$compileProvider`}. + * + * The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}. + * + * @param {string} html HTML input. + * @returns {string} Sanitized HTML. + * + * @example +| Directive | +How | +Source | +Rendered | +
| ng-bind-html | +Automatically uses $sanitize | +<div ng-bind-html="snippet"> |
+ + |
| ng-bind-html | +Bypass $sanitize by explicitly trusting the dangerous value | +
+ <div ng-bind-html="deliberatelyTrustDangerousSnippet()"> +</div>+ |
+ + |
| ng-bind | +Automatically escapes | +<div ng-bind="snippet"> |
+ + |
an html\nclick here\nsnippet
'); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')). + toBe("an html\n" + + "click here\n" + + "snippet
"); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +By enabling this setting without taking other precautions, you might expose your + * application to click-hijacking attacks. In these attacks, sanitized svg elements could be positioned + * outside of the containing element and be rendered over other elements on the page (e.g. a login + * link). Such behavior can then result in phishing incidents.
+ * + *To protect against these, explicitly setup `overflow: hidden` css rule for all potential svg + * tags within the sanitized content:
+ * + *
+ * .rootOfTheIncludedContent svg {
+ * overflow: hidden !important;
+ * }
+ *
+ * | Filter | +Source | +Rendered | +
|---|---|---|
| linky filter | +
+ <div ng-bind-html="snippet | linky">+ |
+ + + | +
| linky target | +
+ <div ng-bind-html="snippetWithSingleURL | linky:'_blank'">+ |
+ + + | +
| linky custom attributes | +
+ <div ng-bind-html="snippetWithSingleURL | linky:'_self':{rel: 'nofollow'}">
+ |
+ + + | +
| no filter | +<div ng-bind="snippet"> |
+ + |