Back to Blog
critical SEVERITY7 min read

How Path Traversal happens in JavaScript i18n loaders and how to fix it

A path traversal vulnerability in `beta/js/i18n-chatrd.js` allowed attackers to manipulate the `lang` URL query parameter to load arbitrary JSON files from the web server by injecting payloads like `../../sensitive-file`. The fix adds input validation to ensure only safe, expected language codes are accepted before they are interpolated into the fetch URL. This type of vulnerability is especially dangerous in internationalization loaders because they are often publicly accessible and designed to

O
By Orbis AppSec
Published August 26, 2026Reviewed August 26, 2026

Answer Summary

This is a path traversal vulnerability (CWE-22) in JavaScript, specifically in the `beta/js/i18n-chatrd.js` i18n loader. The `lang` parameter is read directly from the URL query string and interpolated into a `fetch()` call without validation, allowing attackers to supply payloads like `../../sensitive-file` to retrieve arbitrary JSON files from the server. The fix adds a validation step that sanitizes or allowlists the `lang` parameter before it is used in the fetch URL, preventing traversal sequences from reaching the filesystem.

Vulnerability at a Glance

cweCWE-22
fixValidate the `lang` parameter against an allowlist or strip path traversal sequences before constructing the fetch URL
riskAttackers can read arbitrary files accessible to the web server by manipulating the `lang` URL parameter
languageJavaScript
root causeThe `lang` query string parameter is interpolated directly into a `fetch()` URL without validation or sanitization
vulnerabilityPath Traversal

How Path Traversal Happens in JavaScript i18n Loaders and How to Fix It


Vulnerability at a Glance

Field Detail
Vulnerability Path Traversal
CWE CWE-22
Language JavaScript
Risk Arbitrary file read via manipulated lang URL parameter
Root Cause Unvalidated query parameter interpolated into fetch() URL
Fix Validate lang against an allowlist before constructing the fetch URL

Introduction

The beta/js/i18n-chatrd.js file is responsible for loading internationalization (i18n) language files dynamically — a common and useful pattern in web applications that support multiple locales. The file reads the lang parameter from the URL query string and uses it to fetch the appropriate translation JSON. This is exactly the kind of code that feels harmless at first glance: it's just loading a language file, right?

The problem is that nothing in the original code checked whether lang actually looked like a language code. An attacker who noticed this behavior could replace a benign value like en or fr with a path traversal payload like ../../config/secrets, potentially causing the application to fetch and expose files it was never meant to serve.

This vulnerability was assigned CWE-22: Improper Limitation of a Pathname to a Restricted Directory and rated HIGH severity — a justified rating given how easily it can be triggered with a crafted URL.


The Vulnerability Explained

What the Code Was Doing

The vulnerable pattern in beta/js/i18n-chatrd.js follows a structure like this:

// Vulnerable code (before fix)
const params = new URLSearchParams(window.location.search);
const lang = params.get('lang');

fetch(`/locales/${lang}.json`)
  .then(res => res.json())
  .then(data => { /* load translations */ });

The lang variable is read directly from the URL query string using URLSearchParams and then interpolated into the fetch() URL path without any validation. There is no check that lang is a valid locale identifier, no stripping of special characters, and no allowlist of accepted values.

How an Attacker Exploits This

Because the lang value flows directly into the fetch URL, an attacker can craft a request like:

https://example.com/chat?lang=../../sensitive-file

This causes the browser to fetch:

/locales/../../sensitive-file.json

Which resolves on the server to:

/sensitive-file.json

Depending on the server configuration and what files are accessible at the web root, this could expose:

  • Configuration files containing API keys or database credentials
  • Other JSON files with internal application data
  • Any file the web server has permission to read and serve

The attack requires no authentication, no special tooling, and no prior knowledge beyond the existence of the lang parameter — all of which are easily discoverable by inspecting the page source or network requests.

Why i18n Loaders Are a Common Target

Internationalization loaders are particularly attractive targets for this class of vulnerability because:

  1. They are designed to fetch files dynamically — the file-fetching behavior is intentional, making it easy to overlook the security implications.
  2. They are publicly accessible — language selection is typically available to all users, including unauthenticated ones.
  3. The parameter name is predictablelang, locale, language are standard names that attackers actively probe.

The Fix

The fix adds path validation to the lang parameter before it is used in the fetch() call. The core principle is simple: never trust user input when constructing file paths or URLs.

Before and After

Before (vulnerable):

const params = new URLSearchParams(window.location.search);
const lang = params.get('lang');

// lang is used directly — no validation
fetch(`/locales/${lang}.json`)
  .then(res => res.json())
  .then(data => loadTranslations(data));

After (fixed):

const params = new URLSearchParams(window.location.search);
const lang = params.get('lang');

// Validate lang against an allowlist of known locale codes
const ALLOWED_LANGS = ['en', 'fr', 'de', 'es', 'ja', 'zh'];
const safeLang = ALLOWED_LANGS.includes(lang) ? lang : 'en';

fetch(`/locales/${safeLang}.json`)
  .then(res => res.json())
  .then(data => loadTranslations(data));

Why This Fix Works

By checking lang against an explicit allowlist of valid locale codes before constructing the URL, the fix ensures that:

  • Path traversal sequences like ../ never reach the fetch URL.
  • Unexpected values silently fall back to the default language (en), preserving functionality.
  • The attack surface is eliminated — even a perfectly crafted traversal payload is rejected at the validation step.

An alternative approach that is also effective when a static allowlist is impractical is to validate the format of the lang parameter using a strict regular expression:

// Alternative: regex-based validation for BCP 47 language tags
const langPattern = /^[a-zA-Z]{2,3}(-[a-zA-Z]{2,4})?$/;
const safeLang = langPattern.test(lang) ? lang : 'en';

This approach ensures that only strings matching the pattern of a real language code (e.g., en, en-US, zh-CN) are accepted, blocking any payload containing /, ., or other traversal characters.


Key Takeaways

  • The lang parameter in i18n-chatrd.js was the entry point — a URL query string value that was never validated before being used in a fetch() call.
  • Path traversal in client-side fetch calls is just as dangerous as server-side file reads — the server still resolves the path and serves whatever it finds.
  • Allowlisting locale codes is the correct fix for this specific pattern, because the set of valid language codes is finite and well-known.
  • i18n loaders are a non-obvious attack surface — their dynamic file-loading behavior makes them easy to overlook during security reviews.
  • A regex or allowlist check adds negligible overhead but completely eliminates the traversal risk in this code path.

How Orbis AppSec Detected This

  • Source: The lang parameter read from window.location.search via URLSearchParams.get('lang') in beta/js/i18n-chatrd.js
  • Sink: The unvalidated lang value interpolated directly into a fetch() URL string, e.g., fetch(`/locales/${lang}.json`)
  • Missing control: No allowlist validation, format check, or sanitization was applied to lang before it was used in the URL path
  • CWE: CWE-22 — Improper Limitation of a Pathname to a Restricted Directory
  • Fix: A validation step was added to check lang against an allowlist of permitted locale codes before constructing the fetch URL, with a safe default fallback

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

The path traversal vulnerability in beta/js/i18n-chatrd.js is a clear example of how a small oversight — using a URL parameter without validation — can open a significant security hole. The lang parameter seemed innocuous because its intended use is benign, but the absence of any input validation meant that an attacker could redirect the fetch() call to any JSON file accessible on the server.

The fix is straightforward and the lesson is broadly applicable: every piece of user-supplied input that influences a file path or URL must be validated before use. Allowlisting expected values is the most reliable approach, and for i18n loaders specifically, the set of valid locale codes is always finite and easy to enumerate.

Security vulnerabilities in i18n and localization code are easy to miss because they don't look like traditional attack surfaces. Regular static analysis, code review with a security lens, and automated tools like Orbis AppSec are essential for catching these issues before they reach production.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #9

Related Articles

high

modelExporter.js Path Traversal via Unsanitized Directory Concatenation

A path traversal vulnerability in `modelExporter.js` allowed attackers to read arbitrary files by injecting traversal sequences into directory and relative path parameters. The `readSourceFile` function concatenated these unsanitized inputs directly into file URLs passed to `fetch()`. The fix introduces strict path normalization that rejects attempts to escape the intended directory.

critical

How path traversal happens in PHP virtual filesystem adapters and how to fix it

A critical path traversal flaw in `VirtualAdapter.php`'s `resolveMount()` method allowed attackers to escape mounted directory boundaries using sequences like `../../../etc/passwd`. The fix introduces `PathPolicy::normalizeRelative()` to sanitize the remaining path segment before it ever reaches the underlying storage adapter.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

high

How Trust-Prefix Bypass via Path Traversal Happens in Python Copier and How to Fix It

CVE-2026-53951 is a high-severity path traversal vulnerability in Copier 9.15.0 that allowed attackers to bypass trust-prefix checks and execute tasks without user confirmation. Upgrading to Copier 9.15.2 eliminates this attack vector by properly validating file paths before task execution.

critical

How Path Traversal in basic-ftp Leads to File Overwrite Attacks and How to Fix It

CVE-2026-27699 is a critical path traversal vulnerability in basic-ftp versions before 5.3.1 that allows attackers to overwrite arbitrary files on the system by crafting malicious file paths. This vulnerability was fixed by upgrading basic-ftp and enforcing strict version constraints across dependent packages. Understanding this attack and its mitigation is essential for developers using FTP libraries in production environments.

critical

How Command Injection Vulnerabilities Happen in Python Subprocess Calls and How to Fix Them

A critical command injection vulnerability was discovered in `src/unused/server/fft.py` where external binaries like `oggenc` and `cocoa_text` were executed with file path parameters that could be manipulated by user input. Although `shell=False` was used, the lack of input validation allowed attackers to potentially trigger processing of arbitrary files or cause denial of service. This fix implements proper path validation to prevent exploitation.