See how i18next compares to other vendors in security performance
Copilot said: i18nextify is a JavaScript library that adds i18nextify is a JavaScript library that adds website internationalization via a script tag, without source code changes. Versions prior to 3.0.5 interpolate the lng and ns values directly into the configured loadPath / addPath URL template without any encoding, validation, or path sanitisation. When an application exposes the language-code selection to user-controlled input (the default — i18next-browser-languagedetector reads ?lng= query params, cookies, localStorage, and request headers), an attacker can inject characters that change the structure of the outgoing request URL. This is a single URL-injection vulnerability. The attacker-controlled value is neutralised before it is used as part of an output URL string; the attack shape covers both path traversal and broader URL-structure injection — both are closed by the one interpolateUrl sanitisation fix. This issue has been fixed in version 3.0.5. If users cannot upgrade immediately, they can work around the issue by sanitising lng / ns before they reach i18next (strip .., /, \, ?, #, %, whitespace, and control characters; cap the length).
Impact
i18next-fs-backend ≤ 2.6.5, when used to persist missing translation keys (e.g. via i18next-http-middleware's missingKeyHandler exposed to untrusted input), is vulnerable to prototype pollution via crafted missing-key strings.
Backend.writeFile() splits each queued missing-key string on the configured keySeparator (default .) before calling the internal setPath() walker. The walker (getLastOfPath in lib/utils.js) did not guard against unsafe segments, so a key like "proto.polluted" was split into ["proto", "polluted"] and walked straight into Object.prototype, allowing an attacker to write arbitrary properties onto the global object prototype.
Depending on the host application, polluted prototype properties may cause crashes, corrupted translation behaviour, configuration poisoning, or bypasses of property-based security checks.
Affected configuration
Applications are directly affected only if all of the following hold:
- i18next-fs-backend ≤ 2.6.5 is configured as the backend. - i18next-http-middleware's missingKeyHandler (or another route that forwards untrusted request bodies to i18next.t(..., { ... }) with saveMissing: true) is reachable by untrusted users. - The default behaviour of splitting missing-key strings on keySeparator is in use (i.e. keySeparator is not false).
Apps that do not expose missing-key persistence to untrusted input are not directly affected through this attack path.
Patches
Fixed in i18next-fs-backend 2.6.6. The traversal helper now refuses to descend through proto, constructor, or prototype segments and drops the offending write silently. Legitimate dotted keys (e.g. "header.title") are unaffected.
A matching defence-in-depth fix has been shipped in i18next-http-middleware 3.9.7 — see the companion advisory.
Workarounds
If users cannot upgrade immediately:
- Do not expose i18next-http-middleware's missingKeyHandler to untrusted users (mount it behind authentication, or remove the route). - Disable missing-key persistence (saveMissing: false, or no backend.create implementation) when accepting writes from untrusted input. - Set keySeparator: false in the i18next options to disable backend key splitting (note: this also disables nested translation keys).
Resources
- Original report by @codeswhite. - Companion advisory in i18next-http-middleware: GHSA-f49m-vf83-692w. - Previous i18next-fs-backend security release: GHSA-8847-338w-5hcj (path traversal via lng/ns, fixed in 2.6.4).
Impact
i18next-http-middleware ≤ 3.9.6's missingKeyHandler blocked the literal request-body keys proto, constructor, and prototype (added in 3.9.3, see GHSA-5fgg-jcpf-8jjw), but did not reject dotted variants such as "proto.polluted". Downstream backends that split the missing-key string on a configured keySeparator (notably i18next-fs-backend ≤ 2.6.5) hand these keys to an unguarded setPath() walker that writes to Object.prototype.
Applications that expose missingKeyHandler to untrusted input AND use i18next-fs-backend ≤ 2.6.5 are directly exploitable for remote prototype pollution. Other downstream backends that split the missing-key string the same way may be similarly affected.
Depending on the host application, polluted prototype properties may cause crashes, corrupted translation behaviour, configuration poisoning, or bypasses of property-based security checks.
Patches
Fixed in i18next-http-middleware 3.9.7. A new utils.hasUnsafeKeySegment(key, keySeparator) helper is now used by missingKeyHandler; the configured i18next.options.keySeparator is honoured (default .; false disables segment splitting and only the literal-key denylist applies). Legitimate dotted keys (e.g. "header.title") are unaffected.
The root-cause fix has been shipped in i18next-fs-backend 2.6.6 — see the companion advisory.
Workarounds
If users cannot upgrade immediately:
- Do not expose missingKeyHandler to untrusted users (mount it behind authentication, or remove the route). - Add a request-body filter ahead of the handler that rejects any top-level key containing proto, constructor, or prototype after splitting on a configured keySeparator. - Disable missing-key persistence (saveMissing: false) when accepting writes from untrusted input.
Resources
- Original report by @codeswhite. - Companion advisory in i18next-fs-backend: GHSA-2933-q333-qg83. - Previous i18next-http-middleware security release: GHSA-5fgg-jcpf-8jjw and GHSA-c3h8-g69v-pjrg (in 3.9.3).
i18nextify is a JavaScript library that adds website internationalization via a script tag, without source code changes. Versions prior to 4.0.8 substitute {{key}} interpolation tokens inside src and href attribute values with the raw string returned by i18next.t(). The substitution logic in src/localize.js (the replaceInside handler) only guards against a duplicated http:// origin prefix — it does not validate the URL scheme of the substituted value. A translated value such as javascript:alert(1) or data:text/html,<script>...</script> is applied unchanged to the live DOM attribute when an attacker can influence the content of a translation file or the translation-backend response — for example, via a compromised translation CDN, user-contributed locales, a MITM on a plain-HTTP backend, or write access to the translation JSON. This issue was patched in version 4.0.8.
Affected versions of i18next may fail to sanitize user input when certain configuration options are used. When using the .init method, passing interpolation options without passing an escapeValue will default to undefined rather than the assumed true.
Proof of Concept
js var init = i18n.init({ interpolation: { prefix: "", suffix: "", escapeValue: true } }, function(){ var test = i18n.t('firstName lastName', { firstName: 'Bob', lastName: '["foo","bar"]', }); console.log(test); }); When escapeValue is explicitly passed, the result of test is:
html <script>alert(1)</script> Johnson
This is supposed to be the default. However, if escapeValue is not included, the result is the unescaped string: html <script>alert(1)</script> Johnson
Recommendation
Update to version 3.4.4 or later.
Affected versions of i18next allow untrusted user input to be injected into dictionary key names, resulting in a cross-site scripting vulnerability.
Proof of Concept js var init = i18n.init({debug: true}, function(){ var test = i18n.t('firstName lastName', { escapeInterpolation: true, firstName: 'lastNameHTML', lastName: '<script>', }); console.log(test); }); // equals "<script> <script>"
Recommendation
Update to version 1.10.3 or later.