diff --git a/package-lock.json b/package-lock.json
index d14500932..415fb3801 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4372,6 +4372,11 @@
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz",
       "integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ=="
     },
+    "escape-goat": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz",
+      "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
diff --git a/package.json b/package.json
index 3597ed6a5..d2980e930 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
     "css-loader": "4.0.0",
     "cssnano-webpack-plugin": "1.0.3",
     "dropzone": "5.7.2",
+    "escape-goat": "3.0.0",
     "fast-glob": "3.2.4",
     "file-loader": "6.0.0",
     "fomantic-ui": "2.8.6",
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 30a3d26ce..32fb340dc 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -4,6 +4,7 @@
 import './publicpath.js';
 
 import Vue from 'vue';
+import {htmlEscape} from 'escape-goat';
 import 'jquery.are-you-sure';
 import './vendor/semanticdropdown.js';
 
@@ -25,10 +26,6 @@ import {svg, svgs} from './svg.js';
 
 const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
 
-function htmlEncode(text) {
-  return jQuery('<div />').text(text).html();
-}
-
 let previewFileModes;
 const commentMDEditors = {};
 
@@ -528,12 +525,12 @@ function initCommentForm() {
       switch (input_id) {
         case '#milestone_id':
           $list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>${
-            htmlEncode($(this).text())}</a>`);
+            htmlEscape($(this).text())}</a>`);
           break;
         case '#assignee_id':
           $list.find('.selected').html(`<a class="item" href=${$(this).data('href')}>` +
                         `<img class="ui avatar image" src=${$(this).data('avatar')}>${
-                          htmlEncode($(this).text())}</a>`);
+                          htmlEscape($(this).text())}</a>`);
       }
       $(`.ui${select_id}.list .no-select`).addClass('hide');
       $(input_id).val($(this).data('id'));
@@ -1944,7 +1941,7 @@ function searchUsers() {
         $.each(response.data, (_i, item) => {
           let title = item.login;
           if (item.full_name && item.full_name.length > 0) {
-            title += ` (${htmlEncode(item.full_name)})`;
+            title += ` (${htmlEscape(item.full_name)})`;
           }
           items.push({
             title,
@@ -2220,7 +2217,7 @@ function initTemplateSearch() {
             // Parse the response from the api to work with our dropdown
             $.each(response.data, (_r, repo) => {
               filteredResponse.results.push({
-                name: htmlEncode(repo.full_name),
+                name: htmlEscape(repo.full_name),
                 value: repo.id
               });
             });
@@ -3500,8 +3497,8 @@ function initIssueList() {
               return;
             }
             filteredResponse.results.push({
-              name: `#${issue.number} ${htmlEncode(issue.title)
-              }<div class="text small dont-break-out">${htmlEncode(issue.repository.full_name)}</div>`,
+              name: `#${issue.number} ${htmlEscape(issue.title)
+              }<div class="text small dont-break-out">${htmlEscape(issue.repository.full_name)}</div>`,
               value: issue.id
             });
           });