diff --git a/web/html/src/.eslintrc.js b/web/html/src/.eslintrc.js
index a83436f5a002..5452897c58f4 100644
--- a/web/html/src/.eslintrc.js
+++ b/web/html/src/.eslintrc.js
@@ -72,6 +72,13 @@ module.exports = {
"sort-imports": "off",
// We use a `DEPRECATED_` prefix for old components that doesn't conform with this rule
"react/jsx-pascal-case": "off",
+ "no-restricted-imports": [
+ "error",
+ {
+ name: "node-gettext",
+ message: "Please import from `core/intl/node-gettext` instead.",
+ },
+ ],
...(process.env.NODE_ENV === "production" ? productionRules : {}),
},
diff --git a/web/html/src/core/intl/index.tsx b/web/html/src/core/intl/index.tsx
index 4b0279abb9fe..476f74d3bae4 100644
--- a/web/html/src/core/intl/index.tsx
+++ b/web/html/src/core/intl/index.tsx
@@ -1,6 +1,6 @@
import { createIntl, createIntlCache } from "@formatjs/intl";
-import Gettext from "node-gettext";
+import Gettext from "core/intl/node-gettext";
import { jsFormatPreferredLocale } from "core/user-preferences";
import type { Values } from "./inferValues";
@@ -30,7 +30,7 @@ const alwaysExists = { configurable: true, enumerable: true };
const messages = new Proxy(
{},
{
- get(_, key) {
+ get(_, key: string) {
return gt.gettext(key);
},
getOwnPropertyDescriptor() {
diff --git a/web/html/src/core/intl/node-gettext.ts b/web/html/src/core/intl/node-gettext.ts
new file mode 100644
index 000000000000..919246f13469
--- /dev/null
+++ b/web/html/src/core/intl/node-gettext.ts
@@ -0,0 +1,19 @@
+/**
+ * This module is a basic placeholder stopfix for CVE-2024-21528 in `node-gettext`.
+ * There is currently no patched version available, once a fix is published, please update `node-gettext` and remove
+ * this module and other changes introduced by this commit.
+ */
+// eslint-disable-next-line no-restricted-imports
+import RawGettext from "node-gettext";
+
+export default class Gettext extends RawGettext {
+ addTranslations(locale: string, domain: string, translations: Record) {
+ if (String(locale) === "__proto__") {
+ throw new RangeError("Invalid locale");
+ }
+ if (String(domain) === "__proto__") {
+ throw new RangeError("Invalid domain");
+ }
+ return super.addTranslations.call(this, locale, domain, translations);
+ }
+}
diff --git a/web/html/src/package.json b/web/html/src/package.json
index e6ea3545c931..cd62dde38a64 100644
--- a/web/html/src/package.json
+++ b/web/html/src/package.json
@@ -133,6 +133,7 @@
"@types/jquery": "3.2.0",
"@types/lodash": "^4.14.168",
"@types/node": "14.14.10",
+ "@types/node-gettext": "^3.0.6",
"@types/react": "^16.8.6",
"@types/react-datepicker": "^4.8.0",
"@types/react-dom": "^16.8.6",
diff --git a/web/html/src/yarn.lock b/web/html/src/yarn.lock
index 8517cd30dd08..c7abaeb88caa 100644
--- a/web/html/src/yarn.lock
+++ b/web/html/src/yarn.lock
@@ -2835,6 +2835,11 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
+"@types/node-gettext@^3.0.6":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/@types/node-gettext/-/node-gettext-3.0.6.tgz#2a814953c8e019f7a60cff80853053a19452dbf6"
+ integrity sha512-A0W1IyyW3Ya+Wj6fDDWWwnXWNgrDNvKkq6xKj5Korc7YIo9023LP8qVTzgwQ5SUIANg2Pm2ggA7bfTcwoPPDUQ==
+
"@types/node@*":
version "13.1.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.1.tgz#6d11a8c2d58405b3db9388ab740106cbfa64c3c9"
diff --git a/web/spacewalk-web.changes.eth.CVE-2024-21528 b/web/spacewalk-web.changes.eth.CVE-2024-21528
new file mode 100644
index 000000000000..dc6c1ca6db5f
--- /dev/null
+++ b/web/spacewalk-web.changes.eth.CVE-2024-21528
@@ -0,0 +1 @@
+- Add safeguard against CVE-2024-21528