CVE-2022-23651 (Python, published 2022-02-23T23:15Z)
Description: value: b2-sdk-python is a python library to access cloud storage provided by backblaze. Linux and Mac releases of the SDK version 1.14.0 and below contain a key disclosure vulnerability that, in certain conditions, can be exploited by local attackers through a time-of-check-time-of-use (TOCTOU) race condition. SDK users of the SqliteAccountInfo format are vulnerable while users of the InMemoryAccountInfo format are safe. The SqliteAccountInfo saves API keys (and bucket name-to-id mapping) in a local database file ($XDG_CONFIG_HOME/b2/account_info, ~/.b2_account_info or a user-defined path). When first created, the file is world readable and is (typically a few milliseconds) later altered to be private to the user. If the directory containing the file is readable by a local attacker then during the brief period between file creation and permission modification, a local attacker can race to open the file and maintain a handle to it. This allows the local attacker to read the contents after the file after the sensitive information has been saved to it. Consumers of this SDK who rely on it to save data using SqliteAccountInfo class should upgrade to the latest version of the SDK. Those who believe a local user might have opened a handle using this race condition, should remove the affected database files and regenerate all application keys. Users should upgrade to b2-sdk-python 1.14.1 or later.
Severity: LOW (CVSS v3 base score: 4.7)
Weakness: CWE-367 \u2014 Time-of-check Time-of-use (TOCTOU) Race Condition
The product checks the state of a resource before using that resource, but the resource's state can change between the check and the use in a way that invalidates the results of the check. This can cause the product to perform invalid actions when the resource is in an unexpected state.
Repository: https://github.com/Backblaze/b2-sdk-python
Files changed:
CHANGELOG.md
b2sdk/account_info/sqlite_account_info.py
test/unit/account_info/test_account_info.py
Commit message: Merge pull request from GHSA-p867-fxfr-ph2w

* Fix setting permissions for local sqlite database

Thanks to Jan Schejbal for responsible disclosure!

There used to be a brief moment between creation of the sqlite
database and applying chmod, now there is no such delay.

* Rename self.home to self.test_home in tests

* Actually call the test cleanup

* Add a test for sqlite permissions

* Skip the sqlite chmod test on Windows

Vulnerable code:
        Make sure that the database is created and sets the file permissions.
        # Set the file permissions
        os.chmod(self.filename, stat.S_IRUSR | stat.S_IWUSR)

        self.home = tempfile.mkdtemp()
        for cleanup_method in [lambda: os.unlink(self.db_path), lambda: shutil.rmtree(self.home)]:
                cleanup_method
        with mock.patch('os.environ', env or {'HOME': self.home}):
                'HOME': self.home,
                'USERPROFILE': self.home,
        assert os.path.join(self.home, '.b2_account_info') == actual_path
                    'HOME': self.home,
                    'USERPROFILE': self.home,
                expected_path = os.path.abspath(os.path.join(self.home, '.b2_account_info'))
            default_db_file_location = os.path.join(self.home, '.b2_account_info')
                    'HOME': self.home,
                    'USERPROFILE': self.home,
                    'HOME': self.home,
                    'USERPROFILE': self.home,

Fixed code:
* Fix setting permissions for local sqlite database (thanks to Jan Schejbal for responsible disclosure!)
        Make sure that the database is created and has appropriate file permissions.
        # Prepare a file
        fd = os.open(
            self.filename,
            flags=os.O_RDWR | os.O_CREAT,
            mode=stat.S_IRUSR | stat.S_IWUSR,
        )
        os.close(fd)
import stat
        self.test_home = tempfile.mkdtemp()
        for cleanup_method in [
            lambda: os.unlink(self.db_path), lambda: shutil.rmtree(self.test_home)
        ]:
                cleanup_method()
    @pytest.mark.skipif(
        platform.system() == 'Windows',
        reason='different permission system on Windows'
    )
    def test_permissions(self):
        """
        Test that a new database won't be readable by just any user
        """
        s = SqliteAccountInfo(file_name=self.db_path,)
        mode = os.stat(self.db_path).st_mode
        assert stat.filemode(mode) == '-rw-------'

        with mock.patch('os.environ', env or {'HOME': self.test_home}):
                'HOME': self.test_home,
                'USERPROFILE': self.test_home,
        assert os.path.join(self.test_home, '.b2_account_info') == actual_path
                    'HOME': self.test_home,
                    'USERPROFILE': self.test_home,
                expected_path = os.path.abspath(os.path.join(self.test_home, '.b2_account_info'))
            default_db_file_location = os.path.join(self.test_home, '.b2_account_info')
                    'HOME': self.test_home,
                    'USERPROFILE': self.test_home,
                    'HOME': self.test_home,
                    'USERPROFILE': self.test_home,