diff --git a/package-lock.json b/package-lock.json
index dda23bcbd..db0480a5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,6 @@
         "escape-goat": "4.0.0",
         "fast-glob": "3.3.1",
         "jquery": "3.7.1",
-        "jquery.are-you-sure": "1.9.0",
         "katex": "0.16.8",
         "license-checker-webpack-plugin": "0.2.1",
         "lightningcss-loader": "2.1.0",
@@ -6466,17 +6465,6 @@
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
       "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
     },
-    "node_modules/jquery.are-you-sure": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/jquery.are-you-sure/-/jquery.are-you-sure-1.9.0.tgz",
-      "integrity": "sha512-2r0uFx8CyAopjeHGOdvvwpFP921TnW1+v1uJXcAWQYHYGB1tryTDhQY+5u6HsVeMwbWiRTKVZFWnLaFpDvIqZQ==",
-      "dependencies": {
-        "jquery": ">=1.4.2"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
     "node_modules/js-levenshtein-esm": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz",
diff --git a/package.json b/package.json
index e4f1743fe..224a1422e 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,6 @@
     "escape-goat": "4.0.0",
     "fast-glob": "3.3.1",
     "jquery": "3.7.1",
-    "jquery.are-you-sure": "1.9.0",
     "katex": "0.16.8",
     "license-checker-webpack-plugin": "0.2.1",
     "lightningcss-loader": "2.1.0",
diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js
index d02a82a2e..03169e681 100644
--- a/web_src/js/features/common-global.js
+++ b/web_src/js/features/common-global.js
@@ -1,5 +1,5 @@
 import $ from 'jquery';
-import 'jquery.are-you-sure';
+import '../vendor/jquery.are-you-sure.js';
 import {clippie} from 'clippie';
 import {createDropzone} from './dropzone.js';
 import {initCompColorPicker} from './comp/ColorPicker.js';
diff --git a/web_src/js/vendor/jquery.are-you-sure.js b/web_src/js/vendor/jquery.are-you-sure.js
new file mode 100644
index 000000000..e06da39fc
--- /dev/null
+++ b/web_src/js/vendor/jquery.are-you-sure.js
@@ -0,0 +1,195 @@
+// Fork of the upstream module. The only changes are the addition of `const` on
+// lines 93 and 161 to make it strict mode compatible.
+
+/*!
+ * jQuery Plugin: Are-You-Sure (Dirty Form Detection)
+ * https://github.com/codedance/jquery.AreYouSure/
+ *
+ * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Author:  chris.dance@papercut.com
+ * Version: 1.9.0
+ * Date:    13th August 2014
+ */
+(function($) {
+
+  $.fn.areYouSure = function(options) {
+
+    var settings = $.extend(
+      {
+        'message' : 'You have unsaved changes!',
+        'dirtyClass' : 'dirty',
+        'change' : null,
+        'silent' : false,
+        'addRemoveFieldsMarksDirty' : false,
+        'fieldEvents' : 'change keyup propertychange input',
+        'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])"
+      }, options);
+
+    var getValue = function($field) {
+      if ($field.hasClass('ays-ignore')
+          || $field.hasClass('aysIgnore')
+          || $field.attr('data-ays-ignore')
+          || $field.attr('name') === undefined) {
+        return null;
+      }
+
+      if ($field.is(':disabled')) {
+        return 'ays-disabled';
+      }
+
+      var val;
+      var type = $field.attr('type');
+      if ($field.is('select')) {
+        type = 'select';
+      }
+
+      switch (type) {
+        case 'checkbox':
+        case 'radio':
+          val = $field.is(':checked');
+          break;
+        case 'select':
+          val = '';
+          $field.find('option').each(function(o) {
+            var $option = $(this);
+            if ($option.is(':selected')) {
+              val += $option.val();
+            }
+          });
+          break;
+        default:
+          val = $field.val();
+      }
+
+      return val;
+    };
+
+    var storeOrigValue = function($field) {
+      $field.data('ays-orig', getValue($field));
+    };
+
+    var checkForm = function(evt) {
+
+      var isFieldDirty = function($field) {
+        var origValue = $field.data('ays-orig');
+        if (undefined === origValue) {
+          return false;
+        }
+        return (getValue($field) != origValue);
+      };
+
+      var $form = ($(this).is('form'))
+                    ? $(this)
+                    : $(this).parents('form');
+
+      // Test on the target first as it's the most likely to be dirty
+      if (isFieldDirty($(evt.target))) {
+        setDirtyStatus($form, true);
+        return;
+      }
+
+      const $fields = $form.find(settings.fieldSelector);
+
+      if (settings.addRemoveFieldsMarksDirty) {
+        // Check if field count has changed
+        var origCount = $form.data("ays-orig-field-count");
+        if (origCount != $fields.length) {
+          setDirtyStatus($form, true);
+          return;
+        }
+      }
+
+      // Brute force - check each field
+      var isDirty = false;
+      $fields.each(function() {
+        var $field = $(this);
+        if (isFieldDirty($field)) {
+          isDirty = true;
+          return false; // break
+        }
+      });
+
+      setDirtyStatus($form, isDirty);
+    };
+
+    var initForm = function($form) {
+      var fields = $form.find(settings.fieldSelector);
+      $(fields).each(function() { storeOrigValue($(this)); });
+      $(fields).unbind(settings.fieldEvents, checkForm);
+      $(fields).bind(settings.fieldEvents, checkForm);
+      $form.data("ays-orig-field-count", $(fields).length);
+      setDirtyStatus($form, false);
+    };
+
+    var setDirtyStatus = function($form, isDirty) {
+      var changed = isDirty != $form.hasClass(settings.dirtyClass);
+      $form.toggleClass(settings.dirtyClass, isDirty);
+
+      // Fire change event if required
+      if (changed) {
+        if (settings.change) settings.change.call($form, $form);
+
+        if (isDirty) $form.trigger('dirty.areYouSure', [$form]);
+        if (!isDirty) $form.trigger('clean.areYouSure', [$form]);
+        $form.trigger('change.areYouSure', [$form]);
+      }
+    };
+
+    var rescan = function() {
+      var $form = $(this);
+      var fields = $form.find(settings.fieldSelector);
+      $(fields).each(function() {
+        var $field = $(this);
+        if (!$field.data('ays-orig')) {
+          storeOrigValue($field);
+          $field.bind(settings.fieldEvents, checkForm);
+        }
+      });
+      // Check for changes while we're here
+      $form.trigger('checkform.areYouSure');
+    };
+
+    var reinitialize = function() {
+      initForm($(this));
+    }
+
+    if (!settings.silent && !window.aysUnloadSet) {
+      window.aysUnloadSet = true;
+      $(window).bind('beforeunload', function() {
+        const $dirtyForms = $("form").filter('.' + settings.dirtyClass);
+        if ($dirtyForms.length == 0) {
+          return;
+        }
+        // Prevent multiple prompts - seen on Chrome and IE
+        if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) {
+          if (window.aysHasPrompted) {
+            return;
+          }
+          window.aysHasPrompted = true;
+          window.setTimeout(function() {window.aysHasPrompted = false;}, 900);
+        }
+        return settings.message;
+      });
+    }
+
+    return this.each(function(elem) {
+      if (!$(this).is('form')) {
+        return;
+      }
+      var $form = $(this);
+
+      $form.submit(function() {
+        $form.removeClass(settings.dirtyClass);
+      });
+      $form.bind('reset', function() { setDirtyStatus($form, false); });
+      // Add a custom events
+      $form.bind('rescan.areYouSure', rescan);
+      $form.bind('reinitialize.areYouSure', reinitialize);
+      $form.bind('checkform.areYouSure', checkForm);
+      initForm($form);
+    });
+  };
+})(jQuery);
diff --git a/webpack.config.js b/webpack.config.js
index c6b28068f..f95296c38 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -206,7 +206,6 @@ export default {
         }).join('\n');
       },
       override: {
-        'jquery.are-you-sure@*': {licenseName: 'MIT'}, // https://github.com/codedance/jquery.AreYouSure/pull/147
         'khroma@*': {licenseName: 'MIT'}, // https://github.com/fabiospampinato/khroma/pull/33
       },
       emitError: true,