From 2e505bab20eed89cd4047901e9e604a16b6f3149 Mon Sep 17 00:00:00 2001 From: Artur Zborovskyy Date: Tue, 17 Feb 2026 14:49:01 +0100 Subject: [PATCH 1/2] Fix CWE-23 issue --- tools/i18n/add_fallback_messages.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tools/i18n/add_fallback_messages.py b/tools/i18n/add_fallback_messages.py index 1aaa8524a7..3452e234fd 100644 --- a/tools/i18n/add_fallback_messages.py +++ b/tools/i18n/add_fallback_messages.py @@ -23,18 +23,37 @@ """ import json +import re import sys +from pathlib import Path from typing import Dict, Tuple DEFAULT_LOCALE = 'en' -LOCALE_RELATIVE_PATH = 'static/js/i18n/strings/{locale}/{filename}' +LOCALE_BASE_PATH = (Path(__file__).resolve().parents[2] / 'static' / 'js' / + 'i18n' / 'strings') +LOCALE_RE = re.compile(r'^[A-Za-z0-9_-]+$') +FILENAME_RE = re.compile(r'^[A-Za-z0-9._-]+$') MessageDict = Dict[str, str] BundleDict = Dict[str, MessageDict] +def get_validated_locale_path(locale: str, filename: str) -> Path: + if not LOCALE_RE.fullmatch(locale): + raise ValueError(f'Invalid locale: {locale}') + if not FILENAME_RE.fullmatch(filename) or '/' in filename or '\\' in filename: + raise ValueError(f'Invalid filename: {filename}') + + path = (LOCALE_BASE_PATH / locale / filename).resolve() + try: + path.relative_to(LOCALE_BASE_PATH.resolve()) + except ValueError as err: + raise ValueError(f'Invalid path traversal attempt: {locale}/{filename}') from err + return path + + def extract_messages_from_file(locale: str, filename: str) -> BundleDict: - path = LOCALE_RELATIVE_PATH.format(locale=locale, filename=filename) + path = get_validated_locale_path(locale, filename) with open(path, encoding='utf-8') as f: msg_dict = json.loads(f.read()) return msg_dict @@ -53,7 +72,7 @@ def merge_messages(default_messages: BundleDict, def write_messages(locale: str, filename: str, locale_messages: BundleDict): - path = LOCALE_RELATIVE_PATH.format(locale=locale, filename=filename) + path = get_validated_locale_path(locale, filename) with open(path, 'w', encoding='utf-8') as f: json.dump(locale_messages, f, ensure_ascii=False, indent=2, sort_keys=True) From f66fc1cd734b314cd4240e475233e4963a94d7f2 Mon Sep 17 00:00:00 2001 From: Artur Zborovskyy Date: Mon, 23 Feb 2026 14:04:48 +0100 Subject: [PATCH 2/2] Fix after review --- tools/i18n/add_fallback_messages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/i18n/add_fallback_messages.py b/tools/i18n/add_fallback_messages.py index 3452e234fd..406eef6627 100644 --- a/tools/i18n/add_fallback_messages.py +++ b/tools/i18n/add_fallback_messages.py @@ -41,7 +41,7 @@ def get_validated_locale_path(locale: str, filename: str) -> Path: if not LOCALE_RE.fullmatch(locale): raise ValueError(f'Invalid locale: {locale}') - if not FILENAME_RE.fullmatch(filename) or '/' in filename or '\\' in filename: + if not FILENAME_RE.fullmatch(filename): raise ValueError(f'Invalid filename: {filename}') path = (LOCALE_BASE_PATH / locale / filename).resolve()