Apr 22, 2026·7 min read·4 visits
Unsanitized path parameters in i18next-locize-backend allow attackers to inject path traversal sequences and URL structures, enabling arbitrary endpoint interaction or local file disclosure via the loadPath configuration.
The i18next-locize-backend package prior to version 9.0.2 is vulnerable to path traversal and URL injection via unsanitized template interpolation. Attackers can control parameters such as language or namespace to manipulate API request URLs, potentially leading to arbitrary resource access or local file read.
The i18next-locize-backend package serves as a backend plugin for the i18next internationalization framework, specifically designed to interface with the locize translation management service. This component is responsible for dynamically constructing API request URLs to fetch translation files and submit missing translation keys. These URLs are built using string interpolation based on variables derived from user requests.
Versions of the package prior to 9.0.2 lack proper input validation and sanitization during this URL construction process. The vulnerability manifests when external input sources control the values of configuration variables such as lng (language), ns (namespace), projectId, and version. The absence of boundary checks allows these variables to alter the intended structure of the resulting URL.
This flaw primarily introduces Path Traversal (CWE-22) and URL Injection (CWE-74) risks. The severity of the impact depends heavily on the application's configuration and deployment environment. If the base path utilizes the file:// protocol rather than standard HTTP/HTTPS schemes, the vulnerability escalates to arbitrary file read on the local file system.
The root cause of this vulnerability lies in the naïve implementation of the interpolate() function used by the library to process URL templates. The package utilizes a default template structure formatted as https://api.locize.app/{{projectId}}/{{version}}/{{lng}}/{{ns}}. When a translation request is initiated, the backend resolves these placeholders using an object containing the current context variables.
The vulnerable interpolate() function performs a simple string replacement algorithm. It iterates through the template and replaces any detected {{key}} pattern with the corresponding value from the context object. This operation occurs without any contextual encoding, character filtering, or structural validation of the injected values.
Because parameters like lng and ns are routinely populated from user-controlled sources—such as HTTP headers, query parameters, or route segments—an attacker can supply inputs containing URL control characters. Input values containing sequences like ../, ?, or # are interpolated directly into the endpoint path. This breaks out of the intended path segment and redefines the requested resource hierarchy.
Additionally, the interpolation context relies on a defaults() helper function that previously utilized a for...in loop. This loop iterated over all enumerable properties of an object, including those inherited from the prototype chain. This specific implementation detail created a prototype pollution amplification vector, where an existing prototype pollution vulnerability could be leveraged to poison the interpolation context.
The mitigation strategy introduced in version 9.0.2 replaces the naïve replacement logic with a hardened interpolateUrl() helper and a strict segment validation function. The core of the fix revolves around a "deny-by-default" policy implemented in the isSafeUrlSegment() function. This function serves as a gatekeeper for any string interpolated into a URL path.
The patch explicitly denies segments that are empty or exceed 128 characters, immediately mitigating oversized payload attacks. The validator utilizes precise regular expressions to reject path traversal sequences (..), path separators (/ and \), and URL structure modifiers (?, #, %, @). The inclusion of the % character in the denylist is a critical design choice, as it prevents attackers from using URL-encoded equivalents (e.g., %2e%2e%2f) to bypass the traversal filters.
// Excerpt of the validation logic introduced in 9.0.2
function isSafeUrlSegment(segment) {
if (!segment || typeof segment !== 'string') return false;
if (segment.length === 0 || segment.length > 128) return false;
if (segment.includes('..') || segment.includes('/') || segment.includes('\\')) return false;
if (/[?#%@\s]/.test(segment)) return false;
if (/[\x00-\x1F\x7F]/.test(segment)) return false; // Control characters
const badKeys = ['__proto__', 'constructor', 'prototype'];
if (badKeys.includes(segment)) return false;
return true;
}The update also addresses the prototype pollution risk in the context mapping phase. The interpolate() function was refactored to skip prototype-chain key lookups. The defaults() helper was rewritten to use Object.keys() instead of a for...in loop, restricting iteration strictly to the object's own properties.
Furthermore, the patch introduces defense-in-depth measures against log injection (CWE-117). A new sanitizeLogValue() function removes control characters (\x00-\x1F\x7F) before values are recorded in application logs. A redactUrlCredentials() helper ensures that sensitive URI components, such as HTTP basic authentication credentials, are stripped from log outputs.
Exploitation requires the attacker to identify an application endpoint where user input dynamically influences the language (lng) or namespace (ns) parameters passed to the i18next-locize-backend instance. This control is typically achieved via manipulating the Accept-Language header, URL query parameters, or specific path segments designated for locale routing.
An attacker constructs a payload containing path traversal sequences. For example, submitting ../../malicious-endpoint as the lng parameter transforms the constructed URL from https://api.locize.app/proj/v1/en/ns to https://api.locize.app/proj/v1/../../malicious-endpoint/ns. When the backend issues the HTTP GET request, the client library normalizes the path, resulting in a request to https://api.locize.app/malicious-endpoint/ns.
If the application configures loadPath using the file:// protocol to load translations from disk, the attack surface shifts locally. Injecting ../../../../etc/passwd directly forces the Node.js file system APIs to resolve and read the arbitrary local file. The content of this file is then parsed or logged by the application, leading to resource disclosure.
The injection of URL structure characters allows for query parameter manipulation. By injecting en?api_key=malicious, the attacker forces the backend to append unexpected query parameters to the outgoing request. This technique can be used to override authentication tokens or modify the behavior of the downstream API service.
The primary impact of this vulnerability is unauthorized resource disclosure and arbitrary endpoint interaction. By manipulating the outgoing HTTP requests, attackers can leverage the vulnerable application as an open proxy to interact with unauthorized endpoints on the locize domain or potentially internal network resources if the base URL can be fully overridden.
The most severe consequence occurs in environments utilizing local file loading via the file:// scheme. In these scenarios, the path traversal vulnerability translates directly into an arbitrary file read primitive. Attackers can extract sensitive configuration files, environment variables, or application source code from the host server, leading to a complete compromise of confidentiality.
Secondary impacts include log manipulation and prototype pollution amplification. The ability to inject control characters into the translation variables allows attackers to spoof log entries or obfuscate exploitation attempts. While the prototype pollution amplifier requires an independent pollution vector to be present in the application, its existence in the i18next-locize-backend significantly lowers the complexity of escalating such flaws.
The definitive remediation for this vulnerability is upgrading the i18next-locize-backend package to version 9.0.2 or later. This release contains the comprehensive validation routines and prototype guarding mechanisms required to neutralize the path traversal and injection vectors completely.
If immediate patching is not feasible, developers must implement strict application-level validation on all inputs that influence the i18next language and namespace resolution. Input validation logic should enforce an allowlist approach, ensuring that locale identifiers strictly conform to expected alphanumeric and hyphenated patterns (e.g., ^[a-zA-Z0-9-]+$). All inputs containing path separators, URL reserved characters, or control characters must be rejected before reaching the backend plugin.
Security engineers should review the backend configuration options, specifically the loadPath parameter. Using standard HTTP/HTTPS schemes limits the impact to remote API manipulation. The use of the file:// scheme should be heavily scrutinized and restricted to environments where strict path normalization is enforced by the operating system or runtime context.
| Product | Affected Versions | Fixed Version |
|---|---|---|
i18next-locize-backend locize | < 9.0.2 | 9.0.2 |
| Attribute | Detail |
|---|---|
| Primary CWE | CWE-22: Path Traversal |
| Secondary CWE | CWE-74: URL Injection |
| Attack Vector | Network / Context-Dependent |
| Exploit Status | Proof of Concept |
| Fix Version | 9.0.2 |
| Vulnerable Protocol Risk | file:// scheme arbitrary file read |
Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')