{"id":"CVE-2026-41693","aliases":["EUVD-2026-28793","GHSA-8847-338w-5hcj"],"status":"published","title":"i18next-fs-backend: Path traversal via unsanitised lng/ns allows arbitrary file read/overwrite","description":"i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem. Prior to version 2.6.4, i18next-fs-backend substitutes the lng and ns options directly into the configured loadPath / addPath templates and then read / write the resulting file from disk. The interpolation is unencoded and unvalidated, so a crafted lng or ns value — containing .., a path separator, a control character, a prototype key, or simply an unexpectedly long string — allows an attacker who can influence either value to read or overwrite files outside the intended locale directory. When lng / ns are derived from untrusted input (request-scoped i18next instances behind an HTTP layer such as i18next-http-middleware, or any framework that lets the end user pick the language via query string, cookie, or header), a single request such as ?lng=../../../../etc/passwd causes the backend to attempt to read that path. This issue has been patched in version 2.6.4.","severity":{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00292,"percentile":0.21996,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-22","CWE-73"],"published":"2026-04-22T17:43:14Z","modified":"2026-10-28T02:31:11Z","fixes":[{"ecosystem":"npm","package":"i18next-fs-backend","fixed_in":["2.6.4"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"i18next-fs-backend","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.6.4"}]}]},{"source":"osv","ecosystem":"npm","package":"i18next-fs-backend","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.6.4"}]}]}],"products":[{"vendor":"i18next","product":"i18next-fs-backend"}],"references":[{"url":"https://github.com/i18next/i18next-fs-backend/security/advisories/GHSA-8847-338w-5hcj","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41693","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-8847-338w-5hcj"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41693.json","tags":["advisory"]},{"url":"https://github.com/i18next/i18next-fs-backend","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-41693","title":"i18next-fs-backend: Path traversal via unsanitised lng/ns allows arbitrary file read/overwrite","description":"i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem. Prior to version 2.6.4, i18next-fs-backend substitutes the lng and ns options directly into the configured loadPath / addPath templates and then read / write the resulting file from disk. The interpolation is unencoded and unvalidated, so a crafted lng or ns value — containing .., a path separator, a control character, a prototype key, or simply an unexpectedly long string — allows an attacker who can influence either value to read or overwrite files outside the intended locale directory. When lng / ns are derived from untrusted input (request-scoped i18next instances behind an HTTP layer such as i18next-http-middleware, or any framework that lets the end user pick the language via query string, cookie, or header), a single request such as ?lng=../../../../etc/passwd causes the backend to attempt to read that path. This issue has been patched in version 2.6.4.","status":"published","published":"2026-05-08T15:38:50.525Z","modified":"2026-05-13T17:48:00.613Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high","assessor":"cna"}],"cwes":["CWE-73","CWE-22"],"updated_at":"2026-11-02T13:41:08.498858Z"}],"euvd":[{"id":"EUVD-2026-28793","description":"i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem. Prior to version 2.6.4, i18next-fs-backend substitutes the lng and ns options directly into the configured loadPath / addPath templates and then read / write the resulting file from disk. The interpolation is unencoded and unvalidated, so a crafted lng or ns value — containing .., a path separator, a control character, a prototype key, or simply an unexpectedly long string — allows an attacker who can influence either value to read or overwrite files outside the intended locale directory. When lng / ns are derived from untrusted input (request-scoped i18next instances behind an HTTP layer such as i18next-http-middleware, or any framework that lets the end user pick the language via query string, cookie, or header), a single request such as ?lng=../../../../etc/passwd causes the backend to attempt to read that path. This issue has been patched in version 2.6.4.","status":"published","published":"2026-05-08T15:38:50Z","modified":"2026-05-13T17:48:00Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high"}],"updated_at":"2026-11-02T19:04:33.260537Z"}],"ghsa":[{"id":"GHSA-8847-338w-5hcj","title":"i18next-fs-backend: Path traversal via unsanitised lng/ns allows arbitrary file read/overwrite","description":"### Summary\n\nVersions of `i18next-fs-backend` prior to 2.6.4 interpolate the caller-supplied `lng` and `ns` values directly into the configured `loadPath` and `addPath` templates with no path-component validation and no sanitisation. When an application exposes the resolved language code to user-controlled input (`?lng=` query parameter, cookie, request header), a crafted value can break out of the intended locale directory.\n\nAffected call sites in `lib/index.js`:\n\n- `read` (line 38 pre-patch): `const filename = interpolate(loadPath, { lng: language, ns: namespace })`\n- `removeFile` (line 101 pre-patch): same pattern against `addPath`\n- `writeFile` (line 127 pre-patch): same pattern against `addPath` for queued missing-key writes\n\nThe helper `interpolate` in `lib/utils.js` substitutes raw values with no encoding — unlike the `addQueryString` helper in `i18next-http-backend`, there is no equivalent safety for path interpolation.\n\n### Impact\n\n- **Arbitrary file read.** With a `loadPath` like `/locales/{{lng}}/{{ns}}.json`, an attacker-controlled `lng = '../../etc'` (and matching `ns`) causes the backend to read a file outside the locale directory. For parsers that tolerate arbitrary content (YAML's freeform text), the file contents surface as a translation resource.\n- **Arbitrary file overwrite.** `addPath` is interpolated the same way for missing-key writes (the `create()` code path and the debounced writer in `writeFile`). A traversing `lng`/`ns` combination can cause the process to write JSON structures to an unintended filesystem location, potentially overwriting application files if the process user has write access.\n- **Chain with `.js`/`.ts` eval.** `i18next-fs-backend` supports loading `.js` and `.ts` locale files by `eval`-ing their content (intentional feature, documented as requiring trusted sources). Combining traversal with that path — for example `lng = '../../../app/config'` against `loadPath: '/locales/{{lng}}/{{ns}}.js'` — would cause the backend to **execute** a server-side file as JavaScript, exfiltrating whatever it can touch (`process.env`, connected services).\n\nExploitation requires the application to pass an untrusted `lng`/`ns` value through to `i18next.t()` without its own validation. Many i18next setups do exactly this via `i18next-browser-languagedetector` (query string / cookie detection).\n\n### Affected versions\n\nAll versions of `i18next-fs-backend` prior to **2.6.4**.\n\n### Patch\n\nFixed in **2.6.4**. `lib/utils.js` now exports:\n\n- `isSafePathSegment(v)` — returns `true` only if `v` is a non-empty string of ≤ 128 chars that does not contain `..`, `/`, `\\`, control characters, or a prototype key (`__proto__`, `constructor`, `prototype`). Legitimate i18next language-code shapes (BCP-47, `en_US`, `zh-Hant-HK`, `pirate-speak`, `my-custom.ns`, `+`-joined multi-language values) all pass.\n- `interpolatePath(template, data)` — substitutes variables like the existing `interpolate` but refuses the whole result if any segment fails `isSafePathSegment`. Callers bail out with an error (`read`) or silently drop the queued write (`writeFile`, `removeFile`).\n\nThe `.js` / `.ts` `eval` behaviour is intentionally retained — dynamic expressions in locale files are a documented feature of this backend, and safe replacements like dynamic `import()` are async-only and incompatible with this backend's sync-capable code path. The README has a new \"Security considerations\" section that spells out the trust model: `.js`/`.ts` locale files must be treated as code.\n\n### Workarounds\n\nNo workaround short of upgrading. If you cannot upgrade immediately, sanitise `lng` / `ns` at your application boundary before passing them to i18next — reject values containing `..`, `/`, `\\`, control characters, and cap the length.\n\n### Credits\n\nDiscovered via an internal security audit of the i18next ecosystem.","status":"published","published":"2026-04-22T17:43:14Z","modified":"2026-05-13T13:30:02Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high"}],"cwes":["CWE-22","CWE-73"],"updated_at":"2026-11-02T14:40:07.01746Z"}],"nvd":[{"id":"CVE-2026-41693","description":"i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem. Prior to version 2.6.4, i18next-fs-backend substitutes the lng and ns options directly into the configured loadPath / addPath templates and then read / write the resulting file from disk. The interpolation is unencoded and unvalidated, so a crafted lng or ns value — containing .., a path separator, a control character, a prototype key, or simply an unexpectedly long string — allows an attacker who can influence either value to read or overwrite files outside the intended locale directory. When lng / ns are derived from untrusted input (request-scoped i18next instances behind an HTTP layer such as i18next-http-middleware, or any framework that lets the end user pick the language via query string, cookie, or header), a single request such as ?lng=../../../../etc/passwd causes the backend to attempt to read that path. This issue has been patched in version 2.6.4.","status":"published","published":"2026-05-08T16:16:11.613Z","modified":"2026-06-17T10:47:00.94Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high","assessor":"secondary"}],"cwes":["CWE-22","CWE-73"],"updated_at":"2026-11-02T14:12:17.842772Z"}],"osv":[{"id":"CVE-2026-41693","title":"i18next-fs-backend: Path traversal via unsanitised lng/ns allows arbitrary file read/overwrite","description":"i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem. Prior to version 2.6.4, i18next-fs-backend substitutes the lng and ns options directly into the configured loadPath / addPath templates and then read / write the resulting file from disk. The interpolation is unencoded and unvalidated, so a crafted lng or ns value — containing .., a path separator, a control character, a prototype key, or simply an unexpectedly long string — allows an attacker who can influence either value to read or overwrite files outside the intended locale directory. When lng / ns are derived from untrusted input (request-scoped i18next instances behind an HTTP layer such as i18next-http-middleware, or any framework that lets the end user pick the language via query string, cookie, or header), a single request such as ?lng=../../../../etc/passwd causes the backend to attempt to read that path. This issue has been patched in version 2.6.4.","status":"published","published":"2026-05-08T15:38:50.525Z","modified":"2026-10-28T02:31:11.340867672Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high"}],"cwes":["CWE-22","CWE-73"],"updated_at":"2026-11-02T15:45:03.764807Z"},{"id":"GHSA-8847-338w-5hcj","title":"i18next-fs-backend: Path traversal via unsanitised lng/ns allows arbitrary file read/overwrite","description":"### Summary\n\nVersions of `i18next-fs-backend` prior to 2.6.4 interpolate the caller-supplied `lng` and `ns` values directly into the configured `loadPath` and `addPath` templates with no path-component validation and no sanitisation. When an application exposes the resolved language code to user-controlled input (`?lng=` query parameter, cookie, request header), a crafted value can break out of the intended locale directory.\n\nAffected call sites in `lib/index.js`:\n\n- `read` (line 38 pre-patch): `const filename = interpolate(loadPath, { lng: language, ns: namespace })`\n- `removeFile` (line 101 pre-patch): same pattern against `addPath`\n- `writeFile` (line 127 pre-patch): same pattern against `addPath` for queued missing-key writes\n\nThe helper `interpolate` in `lib/utils.js` substitutes raw values with no encoding — unlike the `addQueryString` helper in `i18next-http-backend`, there is no equivalent safety for path interpolation.\n\n### Impact\n\n- **Arbitrary file read.** With a `loadPath` like `/locales/{{lng}}/{{ns}}.json`, an attacker-controlled `lng = '../../etc'` (and matching `ns`) causes the backend to read a file outside the locale directory. For parsers that tolerate arbitrary content (YAML's freeform text), the file contents surface as a translation resource.\n- **Arbitrary file overwrite.** `addPath` is interpolated the same way for missing-key writes (the `create()` code path and the debounced writer in `writeFile`). A traversing `lng`/`ns` combination can cause the process to write JSON structures to an unintended filesystem location, potentially overwriting application files if the process user has write access.\n- **Chain with `.js`/`.ts` eval.** `i18next-fs-backend` supports loading `.js` and `.ts` locale files by `eval`-ing their content (intentional feature, documented as requiring trusted sources). Combining traversal with that path — for example `lng = '../../../app/config'` against `loadPath: '/locales/{{lng}}/{{ns}}.js'` — would cause the backend to **execute** a server-side file as JavaScript, exfiltrating whatever it can touch (`process.env`, connected services).\n\nExploitation requires the application to pass an untrusted `lng`/`ns` value through to `i18next.t()` without its own validation. Many i18next setups do exactly this via `i18next-browser-languagedetector` (query string / cookie detection).\n\n### Affected versions\n\nAll versions of `i18next-fs-backend` prior to **2.6.4**.\n\n### Patch\n\nFixed in **2.6.4**. `lib/utils.js` now exports:\n\n- `isSafePathSegment(v)` — returns `true` only if `v` is a non-empty string of ≤ 128 chars that does not contain `..`, `/`, `\\`, control characters, or a prototype key (`__proto__`, `constructor`, `prototype`). Legitimate i18next language-code shapes (BCP-47, `en_US`, `zh-Hant-HK`, `pirate-speak`, `my-custom.ns`, `+`-joined multi-language values) all pass.\n- `interpolatePath(template, data)` — substitutes variables like the existing `interpolate` but refuses the whole result if any segment fails `isSafePathSegment`. Callers bail out with an error (`read`) or silently drop the queued write (`writeFile`, `removeFile`).\n\nThe `.js` / `.ts` `eval` behaviour is intentionally retained — dynamic expressions in locale files are a documented feature of this backend, and safe replacements like dynamic `import()` are async-only and incompatible with this backend's sync-capable code path. The README has a new \"Security considerations\" section that spells out the trust model: `.js`/`.ts` locale files must be treated as code.\n\n### Workarounds\n\nNo workaround short of upgrading. If you cannot upgrade immediately, sanitise `lng` / `ns` at your application boundary before passing them to i18next — reject values containing `..`, `/`, `\\`, control characters, and cap the length.\n\n### Credits\n\nDiscovered via an internal security audit of the i18next ecosystem.","status":"published","published":"2026-04-22T17:43:14Z","modified":"2026-05-13T13:50:03.856476Z","cvss":[{"version":"3.1","score":8.2,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N","level":"high"}],"cwes":["CWE-22","CWE-73"],"updated_at":"2026-11-02T15:46:42.077781Z"}]}}
