From 68e33a0031ba0e33b29737d7f220bce1a3501021 Mon Sep 17 00:00:00 2001 From: nazarli-shabnam Date: Thu, 5 Nov 2026 19:39:47 +0400 Subject: [PATCH] fix: anchor account info profile name validation get_user_account_info_path used re.match with an unanchored pattern, so only the first character of the profile name was checked. Use fullmatch so the whole name must be 1-64 allowed characters. --- .../_internal/account_info/sqlite_account_info.py | 2 +- changelog.d/629.fixed.md | 1 + .../unit/account_info/test_sqlite_account_info.py | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 changelog.d/629.fixed.md diff --git a/b2sdk/_internal/account_info/sqlite_account_info.py b/b2sdk/_internal/account_info/sqlite_account_info.py index 1ee7e5a6..02c9ef63 100644 --- a/b2sdk/_internal/account_info/sqlite_account_info.py +++ b/b2sdk/_internal/account_info/sqlite_account_info.py @@ -109,7 +109,7 @@ def _get_xdg_config_path(cls) -> str | None: @classmethod def get_user_account_info_path(cls, file_name: str | None = None, profile: str | None = None): - if profile and not B2_ACCOUNT_INFO_PROFILE_NAME_REGEXP.match(profile): + if profile and not B2_ACCOUNT_INFO_PROFILE_NAME_REGEXP.fullmatch(profile): raise ValueError(f'Invalid profile name: {profile}') profile_file = B2_ACCOUNT_INFO_PROFILE_FILE.format(profile=profile) if profile else None diff --git a/changelog.d/629.fixed.md b/changelog.d/629.fixed.md new file mode 100644 index 00000000..55f5bfdb --- /dev/null +++ b/changelog.d/629.fixed.md @@ -0,0 +1 @@ +Fix account info profile name validation only checking the first character, which let names containing path separators or other invalid characters through to the database path. diff --git a/test/unit/account_info/test_sqlite_account_info.py b/test/unit/account_info/test_sqlite_account_info.py index afb2231f..69c2cdbe 100644 --- a/test/unit/account_info/test_sqlite_account_info.py +++ b/test/unit/account_info/test_sqlite_account_info.py @@ -274,6 +274,21 @@ def test_invalid_profile_name(self): with pytest.raises(ValueError): SqliteAccountInfo.get_user_account_info_path(profile='&@(*$') + @pytest.mark.parametrize( + 'profile', + [ + 'a/../../etc', + 'a\\..\\..\\etc', + 'a b', + 'a&@(*$', + 'a' * 65, + 'abc\n', + ], + ) + def test_invalid_profile_name_with_valid_first_character(self, profile): + with pytest.raises(ValueError): + SqliteAccountInfo.get_user_account_info_path(profile=profile) + def test_profile_and_file_name_conflict(self): with pytest.raises(ValueError): SqliteAccountInfo.get_user_account_info_path(file_name='foo', profile='bar')