Repository navigation
fix(deps): update dependency i18next-http-backend to v4 [security] - #881
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
renovate
Bot
force-pushed
the
renovate/npm-i18next-http-backend-vulnerability
branch
from
October 12, 2026 14:36
da4442e to
6c6e657
Compare
renovate
Bot
force-pushed
the
renovate/npm-i18next-http-backend-vulnerability
branch
from
October 14, 2026 21:33
6c6e657 to
94a6fb6
Compare
renovate
Bot
force-pushed
the
renovate/npm-i18next-http-backend-vulnerability
branch
from
October 20, 2026 11:07
94a6fb6 to
d28d0d9
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
^2.1.1→^4.0.0i18next-http-backend has Path Traversal & URL Injection via Unsanitised lng/ns
CVE-2026-41691 / GHSA-q89c-q3h5-w34g
More information
Details
Summary
Versions of
i18next-http-backendprior to 3.0.5 interpolate thelngandnsvalues directly into the configuredloadPath/addPathURL template without any encoding, validation, or path sanitisation. When an application exposes the language-code selection to user-controlled input (the default —i18next-browser-languagedetectorreads?lng=query params, cookies,localStorage, and request headers), an attacker can inject characters that change the structure of the outgoing request URL.Affected call sites:
_readAny—lib/index.js:64:interpolate(resolvedLoadPath, { lng: languages.join('+'), ns: namespaces.join('+') })create—lib/index.js:123(pre-patch):interpolate(addPath, { lng, ns: namespace })The helper
interpolate(lib/utils.js) previously returned the raw value with no encoding. In contrast,addQueryStringalready correctly usesencodeURIComponentfor each query-string param — only the URL-path substitution was unprotected.Impact
An attacker who can influence the resolved
lngornsvalue can alter the URL in several ways:lng = '../../config'turns/locales//.jsoninto/locales/../../config/translation.json. On a misconfigured web server, this can cause the request to target a different resource than intended; in SSR pipelines that usefile://or similar schemes forloadPath, it can read arbitrary files from the host filesystem.lng = 'en?admin=true'turns/locales//.jsoninto/locales/en?admin=true/translation.json. Some server frameworks parse the query portion with higher priority than the path and branch on attacker-controlled flags.lng = 'en#anything'silently discards the rest of the path in browser fetches (client cannot see the final URL).lng = 'en%2F..', after server-side URL decoding, resolves toen/..— the attacker bypasses the absence of a literal/in their input.The practical worst case is SSRF when
loadPathis an internal or file-scheme URL, and path-based authorisation bypass against servers that segment access by URL prefix.Also fixed in 3.0.5
omitFetchOptions. A module-level boolean inlib/request.jswas flipped totruethe first time any backend instance hit a "not implemented" fetch error. Once flipped, all subsequent requests from all backend instances in the same module silently stripped every user-configured fetch option — including security-relevantcredentials,mode, andcache. One misbehaving instance (for example during SSR hydration or in React Native) permanently removed these protections process-wide. 3.0.5 scopes the flag to the backend'soptionsobject (options._omitFetchOptions) so one instance's fallback cannot pollute siblings.lng/ns. Error callbacks embedded the rawlng/ns/URL in the message string. Crafted CR/LF values could inject fake log lines into file-backed log aggregators (CWE-117). 3.0.5 strips C0/C1 control chars before concatenation.loadPathcontained auser:password@hostauthority, the full URL (including the credentials) ended up in the error message strings returned to the caller. 3.0.5 redactsuser:password@before logging.for...in.addQueryStringand the XHRcustomHeadersloop usedfor...inwhich walks the prototype chain. PollutedObject.prototypeentries could leak into URL query parameters and request headers. 3.0.5 usesObject.keysand an explicit prototype-key guard.Affected versions
All versions of
i18next-http-backendprior to 3.0.5.Patch
Fixed in 3.0.5. Summary of the hardening:
utils.interpolateUrl(used by_readAnyandcreate) returnsnullif any substitution fails the URL-segment safety check (blocks..,/,\,?,#,%,@, whitespace, control chars, prototype keys, and values > 128 chars). Multi-language joins (en+de) are validated per-segment. The call sites now refuse to issue a request when the check fails and call back with a clear error.omitFetchOptionsis stored per-instance onoptions._omitFetchOptions.for...inover untrusted objects replaced withObject.keys+ prototype-key guard.Workarounds
No workaround short of upgrading. If you cannot upgrade immediately, sanitise
lng/nsyourself before they reach i18next (strip..,/,\,?,#,%, whitespace, and control characters; cap the length).Credits
Discovered via an internal security audit of the i18next ecosystem.
Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
i18next-http-backend incomplete URL validation permits SSRF
CVE-2026-105800 / GHSA-xvq9-wjp8-hwqf
More information
Details
There is an SSRF vulnerability when using
i18next-http-backend. A colon in an attacker-controlled language value can make a custom path template request an unintended origin.This is reachable under the following conditions: Attacker controls i18next language or namespace input that is interpolated into loadPath.
Proof of Concept
Run:
The expected result is:
Why the Previous Patch Was Incomplete
This vulnerability is caused by an incomplete patch for CVE-2026-41691. The previous patch addressed the following behavior: Original hardening blocks path traversal and selected URL-control characters in lng/ns.
The following bypass remains in the current release: lng=http:127.0.0.1: with loadPath=/.json; colon is not blocked and produces an outbound request.
Impact
The attacker-controlled language or namespace value can redirect the backend request to an unintended origin, resulting in URL injection and possible SSRF.
Recommended Fix
Parse the final URL and require it to remain within the intended origin and path. If absolute URLs are supported, validate them against an explicit allowlist.
Please let us know if you need any additional information or clarification. We are happy to prepare a pull request if that would be helpful. Thank you for reviewing this report.
Maintainer note
Confirmed and fixed in 4.0.2 (commit i18next/i18next-http-backend@07e0288).
Preconditions. The bypass only works when the
loadPath/addPathtemplate begins directly withor— no origin and no leading/, e.g./.json. Only in that position ishttp:parsed as a URL scheme. The default/locales//.jsonand every template with a leading path or origin are not affected: a colon inside a path segment has no structural meaning there, and the resulting string is rejected as an invalid URL. The same template shape also allowed annsvalue such as//evil.example/xto become a protocol-relative URL in browsers.Fix.
:is now rejected in bothlngandnsvalues, and//innsvalues. No BCP-47 language code contains a colon, and:is i18next's default namespace separator, so no usable namespace name does either.Affected range. Versions before 3.0.5 had no validation at all and are reachable through this vector too, so the affected range is
< 4.0.2rather than>= 3.0.5, <= 4.0.1.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:NReferences
This data is provided by the GitHub Advisory Database (CC-BY 4.0).
Release Notes
i18next/i18next-http-backend (i18next-http-backend)
v4.0.2Compare Source
Security release. See advisory GHSA-xvq9-wjp8-hwqf.
:inlngandnsvalues, and//innsvalues. With aloadPath/addPathtemplate that starts with the placeholder (e.g.{{lng}}/{{ns}}.json— no origin and no leading/), a value such ashttp:127.0.0.1:8080was interpolated into an absolute URL and the request left the intended origin (SSRF / URL injection). The default/locales/{{lng}}/{{ns}}.jsonand every template with a leading path or origin were not affected, because a colon inside a path segment has no structural meaning there. No BCP-47 language code contains:, and:is i18next's defaultnsSeparator, so no usable namespace name does either — the tightened check has no legitimate collateral.v4.0.1Compare Source
@innsvalues so scoped-package-style namespace names such as@organization/package-namefetch correctly again (#191). 3.0.6 relaxed thenscheck for/but left@in the shared denylist. In the URL path position@is a plain RFC 3986 pchar with no structural meaning; it stays blocked forlng, where it marks the userinfo/authority boundary. Every other pattern from the 3.0.5 advisory (..,\,%,?,#, whitespace, control chars, prototype keys, oversized inputs) remains blocked for both keys.v4.0.0Compare Source
cross-fetchdependency.i18next-http-backendnow requires a host-providedfetch. This is available in Node ≥ 18 (stable since Node 21), all modern browsers, Deno, and Bun. For runtimes without nativefetch, install a ponyfill yourself and inject it viaoptions.alternateFetch, or stay on v3.x.engines.node = ">=18").lib/request.js— usesglobalThis(withglobal/windowfallbacks for legacy embedded runtimes) instead of separateglobal.*/window.*branches per API. XHR / ActiveXObject are still picked up if the host provides them, but no longer polyfilled."sideEffects": falsefor better tree-shaking by downstream bundlers.tsdown(rolldown + oxc). One config produces ESM, CJS, and the IIFE browser bundles. Drops@babel/cli,@babel/core,@babel/preset-env,babel-plugin-add-module-exports,browserify,uglify-js, thefixcjsrewrite hack, and the--ignore cross-fetchbrowserify flag. Side benefit: minified browser bundle shrinks from ~13 KB to ~6.8 KB (oxc minifier + no babel runtime helpers).index.jsper format (previously one file perlib/*.jsmodule). The package'sexportsmap is unchanged, so this is invisible to consumers using documented entry points.eslint-config-standard(+ five plugins) withneostandardand migrated to ESLint 9 flat config (eslint.config.mjs). Removed deprecatedtslintanddtslint—test:typescriptnow runstsc --noEmitplustsd..npmignore— published tarball no longer includes the sourcelib/, the build configs (tsdown.config.ts,eslint.config.mjs,tsconfig.json), or the rootindex.jsre-export shim. Drops from 21.3 KB → ~17 KB packed.alternateFetchis now documented in the README options block as the supported escape hatch for fetch ponyfills, test mocking, and request interception. v4 migration note added to "Getting started".v3.0.6Compare Source
nsvalues so nested namespace names (mapping to URL layouts such as/locales/en/a/b.json) fetch correctly again. 3.0.5's security fix applied the same strict URL-segment check to bothlngandns, which was correct forlng(no BCP-47 shape contains/) but over-strict forns— nested namespaces containing/were never officially supported, but the behaviour fell out of the implicit string-substitution semantics ofloadPathand is common enough in the wild to be worth accommodating.isSafeUrlSegmentis now split intoisSafeLangUrlSegment(strict — still rejects/) andisSafeNsUrlSegment(loose — allows/but still rejects..,\, URL-structure characters, control chars, prototype keys, and oversized inputs).isSafeUrlSegmentis kept as a backwards-compatible alias for the strict check. The 3.0.5 security fix remains in force for every concrete attack pattern from the original advisory.v3.0.5Compare Source
Security release — all issues found via an internal audit. See published advisory GHSA-q89c-q3h5-w34g.
lngornsvalues contain path-traversal, URL-structure (?,#,%,@, whitespace), path separators, control characters, prototype keys, or exceed 128 chars. Prevents path traversal / SSRF / URL injection via attacker-controlled language-code values.isSafeUrlSegmentis permissive for legitimate i18next language codes (any BCP-47-like shape, underscores, hyphens, dots,+-joined multi-language requests) (GHSA-q89c-q3h5-w34g)omitFetchOptions— the fetch-options-stripping fallback is now scoped to a single backend instance viaoptions._omitFetchOptionsinstead of a module-level boolean. One instance hitting a "not implemented" fetch error no longer permanently stripsrequestOptions(includingcredentials,mode,cache) from every other backend instance in the same processlng/ns/ URL values before they appear in error-callback strings (CWE-117 log forging)user:passwordcredentials from URLs before including them in error-callback strings — prevents leaking basic-auth credentials embedded inloadPath/addPathObject.keys+ prototype-key guard) inaddQueryStringand in thecustomHeadersloop in XHR mode — prevents prototype-pollution amplification into the URL and request headers.env*and*.pem/*.keyfiles in.gitignorev3.0.4Compare Source
{{lng}}and{{ns}}placeholders are supported; custom interpolation prefix/suffix from i18next config no longer applies to backend pathsv3.0.2Compare Source
v3.0.1Compare Source
v3.0.0Compare Source
i18next-http-backend/cjsexport or stay at v2.6.2 or v2.7.1v2.7.3Compare Source
v2.7.2Compare Source
v2.7.1Compare Source
v2.7.0Compare Source
v2.6.2Compare Source
v2.6.1Compare Source
v2.6.0Compare Source
v2.5.2Compare Source
v2.5.1Compare Source
v2.5.0Compare Source
v2.4.3Compare Source
v2.4.2Compare Source
v2.4.1Compare Source
v2.4.0Compare Source
v2.3.1Compare Source
v2.3.0Compare Source
v2.2.2Compare Source
v2.2.1Compare Source
v2.2.0Compare Source
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.