Jun 25, 2026·7 min read·18 visits
Unauthenticated prototype pollution in i18next-fs-backend < 2.6.6 via missing translation key traversal can lead to RCE or DoS.
A critical prototype pollution vulnerability exists in the i18next-fs-backend Node.js package (prior to version 2.6.6) through its translation persistence layer. When handling missing translation keys, insecure traversal of JSON objects via the getLastOfPath function allows remote, unauthenticated attackers to mutate Object.prototype, potentially leading to denial of service, security bypasses, or remote code execution.
i18next-fs-backend is an open-source backend connector for the Node.js i18next ecosystem designed to load and persist translations using the file system. In enterprise deployments, localized web applications leverage this component to dynamically cache and update language keys on local storage or network-attached shares. The library exposes a write-path capability through functions such as setPath and pushPath, typically invoked by upstream translation middleware to persist missing translation keys requested by clients.\n\nThe primary attack surface is introduced when applications expose the missing translation interface directly to remote users. This is standard behavior for integrations using middleware containing a missing key handler, where dynamic payloads dictate which keys to record. When input validation is missing on these external endpoints, remote attackers can submit specially crafted strings that route directly to the backend filesystem writer.\n\nThis vulnerability class is improper control of generation of prototype attributes, commonly classified as CWE-1321. The backend implementation traverses internal translation object graphs without enforcing boundaries on the properties retrieved from the prototype chain. This lack of restriction allows an unauthenticated remote attacker to compromise the integrity of the host runtime by writing arbitrary properties to global prototypes, leading to global configuration poisoning or application instability.
The root cause of this vulnerability lies in the in-memory JSON object traversal logic implemented in lib/utils.js. Specifically, the helper function getLastOfPath is used to navigate deep nested objects using keys parsed from input paths. When handling missing translation keys, the application splits the key string into individual segments using a configurable character sequence, which defaults to a period.\n\nThe function processes these segments sequentially within a loop, using each segment as a property lookup key against the current node object. When the key segment contains reserved prototype property names, the lookup resolves to the object prototype rather than an isolated data property. Because the implementation did not perform safety checks to verify that properties belonged to the object's own direct namespace, the walker descended directly into the prototype chain.\n\nWhen getLastOfPath finishes traversing the segments, it returns a reference to the final parent object and the target leaf key. Upstream callers then assign the user-provided translation value directly to this returned object reference. If the object reference points to the global object prototype, this assignment mutates the execution context of the entire application, introducing global prototype pollution.
The vulnerable version of getLastOfPath fails to validate key segments against a blocklist or check ownership of the target properties. The loop shifts elements from the stack array and assigns the next cursor without validating if the property matches internal JS keywords.\n\njavascript\n// Vulnerable Implementation\nfunction getLastOfPath (object, path, Empty) {\n const stack = typeof path === 'string' ? path.split('.') : path.slice()\n \n while (stack.length > 1) {\n if (!object) return {}\n\n const key = cleanKey(stack.shift())\n if (!object[key] && Empty) object[key] = new Empty()\n object = object[key] // Vulnerable: Resolves __proto__ and prototype directly\n }\n\n if (!object) return {}\n return {\n obj: object,\n k: cleanKey(stack.shift())\n }\n}\n\n\nThe patch mitigates this risk by establishing an explicit check against a list of unsafe keys prior to resolving the object lookup. The UNSAFE_KEYS array blocks the properties proto, constructor, and prototype from being resolved by the path crawler. If any segment matches these keywords, the function returns an empty structure and drops downstream assignments.\n\njavascript\n// Patched Implementation\nconst UNSAFE_KEYS = ['__proto__', 'constructor', 'prototype']\n\nfunction getLastOfPath (object, path, Empty) {\n const stack = typeof path === 'string' ? path.split('.') : path.slice()\n \n while (stack.length > 1) {\n if (!object) return {}\n\n const key = cleanKey(stack.shift())\n // Secure guard: Drop traversal if an unsafe property is identified\n if (UNSAFE_KEYS.indexOf(key) > -1) return {}\n if (!object[key] && Empty) object[key] = new Empty()\n object = object[key]\n }\n\n if (!object) return {}\n const k = cleanKey(stack.shift())\n if (UNSAFE_KEYS.indexOf(k) > -1) return {}\n return { obj: object, k }\n}\n
Exploitation of CVE-2026-48713 is straightforward and does not require active authentication if the application exposes the missing keys collection endpoint. An attacker starts by crafting an HTTP request containing a query or body payload where the missing key matches the payload sequence. This string represents the path to the prototype attribute the attacker intends to inject into the global runtime.\n\nWhen the upstream server processes the translation request, the server identifies the lookup failure and invokes the persistence handler. The handler sends the key string to the filesystem backend, triggering the vulnerable traversal algorithm in getLastOfPath. The split path resolves the first key segment, shifting the target object context to the application prototype before executing the property assignment.\n\nmermaid\ngraph LR\n A["Attacker Payload: __proto__.polluted"] --> B["i18next Middleware Endpoint"]\n B --> C["Backend.writeFile() Split Key"]\n C --> D["getLastOfPath() Traversal Loop"]\n D --> E["Object.prototype Mutated"]\n\n\nIn standard Node.js applications, successful exploitation results in the creation of a persistent property on Object.prototype. The global mutation infects all subsequently created plain JavaScript objects, which immediately inherit this injected property. This enables attackers to control configuration variables or modify program control flow across separate application features.
The security impact of prototype pollution in Node.js environments depends heavily on the surrounding application logic and installed package dependencies. An attacker can use this vulnerability to achieve remote code execution (RCE) by targeting template engines or process execution libraries. These libraries often check for optional configuration parameters on generic options objects, which can be hijacked via prototype injection.\n\nFor example, if the target application uses libraries like child_process or template utilities that compile code dynamically, injecting attributes such as shell or outputFunctionName can force the application to run arbitrary shell commands. Alternatively, attackers can inject keys to alter authorization checks, such as establishing an isAdmin property that defaults to true on all empty objects.\n\nIf RCE is not viable, the vulnerability can be exploited to cause a widespread Denial of Service (DoS). Injecting properties that overwrite standard object methods like toString or valueOf will cause immediate errors during JSON serialization or logging routines. This results in continuous application crashes whenever the runtime attempts to manipulate basic data structures.
The vulnerability is addressed in i18next-fs-backend version 2.6.6. The primary fix pattern introduces a blocklist filter that stops the traversal mechanism from executing lookup operations against JavaScript's default inheritance keywords. It prevents standard prototype manipulation by rejecting pathways using proto, prototype, or constructor attributes.\n\nThis fix strategy is highly effective for standard Node.js prototype pollution paths, as it blocks the direct vectors required to navigate to Object.prototype. The implementation silently discards any write operations that attempt to utilize these forbidden keys, protecting the application without interrupting execution flow. Security teams should verify that custom wrappers around the library do not override the default parser logic or introduce alternate path splitters.\n\nFor complete protection, deployment teams must audit all dependencies within the translation workflow, upgrading i18next-http-middleware alongside the core backend driver. If upgrading is not possible, security administrators must disable the saveMissing configuration property. This effectively closes the untrusted input vector by preventing the backend translation persistence layer from receiving client-supplied keys.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
i18next-fs-backend i18next | < 2.6.6 | 2.6.6 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1321 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 | 9.1 (Critical) |
| EPSS Score | 0.00419 (33.50th percentile) |
| Exploit Status | PoC Available |
| CISA KEV | Not Listed |
The application receives input from an upstream component but does not restrict or sanitize properties before modifying the attributes of a prototype on that object.
A symbolic link directory traversal vulnerability was identified in go-git, a pure Go implementation of the Git specification. This vulnerability allows an attacker to construct a repository that, when checked out or processed, bypasses directory boundaries to write or overwrite arbitrary files on the host filesystem.
CVE-2026-71557 is a path traversal vulnerability in go-git, a pure-Go implementation of Git. In vulnerable versions, the filesystem-backed storage engine fails to validate reference names before mapping them to on-disk paths. An attacker hosting a malicious Git server can advertise references containing directory traversal sequences, such as 'refs/heads/../../config', to write or overwrite files outside the intended reference storage directory.
An information disclosure vulnerability in the Nuxt development server allows adjacent network attackers to retrieve the absolute project root directory and a persistent workspace UUID by querying the unprotected Chrome DevTools workspace endpoint. This occurs when the development server is bound to a network-reachable interface, allowing requests that bypass the header-based security verification checks.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in SvelteKit's content negotiation header parser prior to version 2.70.2. An unauthenticated remote attacker can exploit this vulnerability by sending a crafted Accept header with highly repetitive malformed values. This triggers catastrophic backtracking on the single-threaded Node.js/Bun event loop, leading to CPU exhaustion and full denial of service.
An OS command injection vulnerability exists in the npm package loading component of the jsii-diff CLI tool within the AWS jsii framework. Prior to version 1.131.0, when parsing package specifiers prefixed with `npm:`, the tool concatenated user-controlled inputs directly into a shell execution string via child_process.exec. This allows attackers to execute arbitrary shell commands under the context of the running Node.js process.
CodeIgniter4 versions prior to v4.7.4 contain a protocol-spoofing vulnerability due to improper verification of upstream reverse proxy forwarding headers. Remote, unauthenticated attackers can inject headers like X-Forwarded-Proto to deceive the framework into identifying an insecure HTTP request as a secure HTTPS connection.