diff --git a/services/web/app/views/project/editor/chat.pug b/services/web/app/views/project/editor/chat.pug
index a560f81724..e9460d9e78 100644
--- a/services/web/app/views/project/editor/chat.pug
+++ b/services/web/app/views/project/editor/chat.pug
@@ -41,6 +41,7 @@ aside.chat(
.message-content
p(
mathjax,
+ mathjax-allow-html="true",
ng-repeat="content in message.contents track by $index"
)
span(ng-bind-html="content | linky:'_blank':{rel: 'noreferrer noopener'}")
diff --git a/services/web/public/src/directives/mathjax.js b/services/web/public/src/directives/mathjax.js
index 854b44a578..96bbf4eab4 100644
--- a/services/web/public/src/directives/mathjax.js
+++ b/services/web/public/src/directives/mathjax.js
@@ -1,15 +1,19 @@
/* global MathJax, _ */
define(['base'], function(App) {
- return App.directive('mathjax', function($compile) {
+ return App.directive('mathjax', function($compile, $parse) {
return {
link(scope, element, attrs) {
if (!(MathJax && MathJax.Hub)) return
- const mathJaxContents = element.html()
- const nonBindableEl = $compile('')({})
- element.html('').append(nonBindableEl)
- nonBindableEl.html(mathJaxContents)
+ // Allowing HTML can be unsafe unless using something like
+ // `ng-bind-html` because of potential Angular XSS via {{/}}
+ if (!$parse(attrs.mathjaxAllowHtml)(scope)) {
+ const mathJaxContents = element.html()
+ const nonBindableEl = $compile('')({})
+ element.html('').append(nonBindableEl)
+ nonBindableEl.html(mathJaxContents)
+ }
if (attrs.delimiter !== 'no-single-dollar') {
const inlineMathConfig =