Jun 25, 2026·7 min read·3 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 critical vulnerability exists in MessagePack-CSharp's typeless deserialization mechanism where configured blocklists fail to recursively inspect nested types. An attacker can bypass security restrictions by wrapping unauthorized types in arrays or generic collections, allowing insecure deserialization and remote code execution.
CVE-2026-48708 details a critical concurrency synchronization flaw in OliveTin versions < 3000.13.0. A shared package-level text/template.Template instance is accessed concurrently across multiple goroutines without proper synchronization. When concurrent request processing occurs, a race condition causes Go runtime panics or command contamination across separate sessions, enabling denial of service or execution of contaminated commands.
A missing authorization vulnerability in the OliveTin system allows unauthenticated remote actors to query the ValidateArgumentType RPC endpoint. By exploiting this flaw, attackers can execute systematic brute-force and side-channel validation attacks to enumerate active action binding IDs, parameter structures, and operational metadata, bypassing configured guest authentication barriers.
An observable timing discrepancy vulnerability (CWE-208) in Filament's administrative login page allows unauthenticated remote attackers to determine the existence of registered email addresses. This timing side-channel arises from short-circuiting logic that skips expensive password hashing checks when a queried email address is not found in the database. Attackers can execute statistical timing attacks to map active administrator accounts, facilitating subsequent targeted brute-force or credential-stuffing campaigns.
Filament's ImageColumn (used in tables) and ImageEntry (used in infolists) components render database values inside HTML attributes without validation or sanitization. This allows an attacker to inject arbitrary HTML attributes, leading to Stored Cross-Site Scripting (XSS).
The Netty incubator codec for Oblivious HTTP (OHTTP) fails to verify that a cryptographically signed final chunk is received before the outer HTTP body terminates. This missing validation allows an on-path adversary to truncate chunked-OHTTP messages cleanly at a non-final chunk boundary, leading to undetected data truncation and compromising message integrity. The vulnerability affects multiple versions of the maven package io.netty.incubator:netty-incubator-codec-ohttp prior to 0.0.22.Final.