low

CVE-2026-112913

PyPI · filelock

Summary

filelock: ReadWriteLock on Windows acts on SQLite side files another local user places beside its database

Severity
low
CVSS
3.3
CWE
CWE-367
Also known as
GHSA-9vhv-jxww-xfm5
Published
2026-10-23
Updated
2026-10-23

Advisory details

On Windows, ReadWriteLock and AsyncReadWriteLock (the SQLite-backed reader/writer lock) connect SQLite to the lock database by its path, in every directory. SQLite derives three side files from that path: <database>-journal, the rollback journal (pages saved to undo an interrupted write); <database>-wal, the write-ahead log (changes kept outside the main file); and <database>-shm, the shared-memory index of the WAL. SQLite acts on whichever of these it finds beside the database before the lock runs any statement. Another local account that can create files in the database's directory, but not delete files of other accounts there, places such a side file beside the database and denies everyone DELETE on it, which a file's creator may do. C:\Windows\Temp (the temporary directory of services, granting BUILTIN\Users create but not delete) and C:\Users\Public are such directories.

With a -wal in place, every read_lock() and write_lock() of the user running the lock (below: the lock user) raises sqlite3.OperationalError: disk I/O error at once, whatever timeout says, until that account removes its file; the lock user cannot. With a -journal beside a lock database that holds a table, SQLite replays the journal and deletes the file the journal names, a file of the lock user, and the acquire reports success. Affected versions are filelock 3.20.4 through 4.2.0 on Windows. The maintainers found this while reviewing the fix for the POSIX form of the defect, GHSA-v4x8-3wr5-3wq8, whose text says "Windows does not take this path" (review round 4, finding F2 of set D). It is not among the findings of the report Anthropic's OSS Scanner sent on 15 October 2026.

Severity

CVSS 3.1 CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L scores 3.3 (Low).

AV:L (local): the other account needs a logon on the same host. AC:L (low attack complexity): create one file beside the database and set its ACL (access control list); no race, and the other account can place the file days earlier. PR:L (low privileges): an ordinary account that can create files in the directory is enough. UI:N (no user interaction). S:U (scope unchanged). C:N (no confidentiality impact): the other account learns nothing. I:N (no integrity impact in the scored variant): see the scoring note. A:L (partial availability impact): every acquire fails with an exception that Timeout handlers do not catch, until the other account removes its file; no crash, and the lock's own data is not changed.

Scoring note. The deletion variant reads CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:L (3.6): I:L because the lock user's process deletes one file the journal names, AC:H because it needs a lock database that holds a table, which filelock does not create, and a journal the lock user can open for writing. The lower-reading rule of this advisory set scores the variant that reaches every ReadWriteLock on Windows in such a directory, 3.3, and describes the deletion variant under Mechanism. Classification from the review: security (another account), availability for the scored variant.

Scope and preconditions

Affected code

Scanned commit b831496b0273: the Windows branch of _connect checks the database through a handle and then calls sqlite3.connect(database, ...) with the path. _open_lock_database and _raise_if_wal inspect that handle, not the side files. The first statement is PRAGMA busy_timeout=...; PRAGMA journal_mode=MEMORY; at L816. _do_acquire_inner at L763 turns only "database is locked" into Timeout; any other sqlite3.OperationalError leaves the acquire.

Introduced

cfd4446 "feat(lock): add SQLite-based ReadWriteLock" (#399, 2026-02-12), first tag 3.20.4 (verified with git tag --contains), passed the lock path to sqlite3.connect on every platform. The Linux descriptor route (4.0.9) and the macOS hard-link route (4.1.1) did not change Windows, where the connect has been by name in every release since. The reproducer ran against the head of PR #834 at 1f9e415, whose Windows branch of _connect is the same code as at b831496b0273.

Mechanism

_connect on Windows opens the database with _open_non_reparse_fd, checks through that handle that the file is a regular file, not a reparse point, and that its header does not declare WAL mode, and keeps the handle open while sqlite3.connect(database) opens the same name. The check covers the database, not the names beside it. On the first statement, PRAGMA journal_mode=MEMORY, SQLite takes its first lock on the database and looks for <database>-wal. A non-empty -wal beside a database that is not in WAL mode is a leftover SQLite deletes. The other account's file denies DELETE, so the pragma raises SQLITE_IOERR_DELETE, which reaches the caller as sqlite3.OperationalError: disk I/O error. _do_acquire_inner converts only "database is locked" into Timeout, so acquire_read(), acquire_write() and the async forms raise at once, on every call, until the file is gone. The lock user has no right to delete it.

The journal variant needs a database with content. Beside a non-empty database SQLite treats a <database>-journal with a valid header as hot (left by an interrupted write) and replays it before the first statement runs. The review's journal is 46 bytes: a file path, its 4-byte length, the 4-byte sum of its bytes and SQLite's journal magic. That tail names a super-journal, and recovery ends by deleting the file it names. The lock user's write_lock() therefore deletes one file the other account chose, provided the lock user ca

References

Related advisories

Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.

Check my repo

Summarize with AI

ChatGPTClaudePerplexity

Sources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.