Live › vulnerability › CVE-2026-112913
Go to dashboardOn Windows, filelock's SQLite-backed ReadWriteLock opens its database by path, so SQLite acts on a -wal or -journal file another local account placed beside it in a shared directory such as C:\Windows\Temp. The lock user's acquires then fail on every call with a disk I/O error, or in the journal variant SQLite deletes a file the lock user can delete.
Summary written from the sources below. Check the originals before acting.
First seen by InfraStack 2026-10-23 22:35 UTC. All times on this page are UTC.
Windows hosts running filelock 3.20.4 through 4.2.0 whose ReadWriteLock or AsyncReadWriteLock database lives in a directory where another local account can create files but not delete the lock user's files. Directories only the lock user can write are not affected, and Linux and macOS take other code paths covered by a separate advisory.
| Product | Ecosystem | Affected | Fixed in |
|---|---|---|---|
| filelock | pypi | >= 3.20.4, <= 4.2.0 | 4.2.1 |
pip show filelock and confirm the version is between 3.20.4 and 4.2.0 on Windows.ReadWriteLock(...)) sits in a directory such as C:\Windows\Temp or C:\Users\Public where other accounts can create files.<database>-wal, <database>-journal or <database>-shm files beside lock databases.4.2.1.%LOCALAPPDATA%.Each row is the first time that source carried this signal. The analyst’s rows are its own findings.
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.
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.
ReadWriteLock and AsyncReadWriteLock, both of which connect through _connect. On Linux and macOS the lock takes other routes, covered by GHSA-v4x8-3wr5-3wq8.C:\Windows\Temp carries BUILTIN\Users:(CI)(S,WD,AD,X) (create file and create subdirectory, no delete child); C:\Users\Public and any directory with such an entry qualify. A directory only the lock user can write, such as %LOCALAPPDATA% or the per-user temporary directory, is not affected.<database>-wal, grants everyone modify and denies everyone DELETE on it. A file's creator may set both. The lock user can open and read the file but not delete it.<database>-journal grants the lock account modify rights. The journal's tail names a file the lock user can delete.write_lock(timeout=1) raised sqlite3.OperationalError: disk I/O error with the undeletable -wal in place; with the writable journal the acquire succeeded and the named file was gone; with an undeletable journal every acquire raised .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.
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.
_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
This page as .md · .json · in your agent: get_signal("CVE-2026-112913")
GitHub Advisory Database, CC-BY 4.0. Posts quoted belong to their authors.
sqlite3.OperationalError: unable to open database fileWindowsFileLock, in its symlink paragraph; the ReadWriteLock documentation names no directory requirement on Windows.