A vulnerability in filelock versions >=6.1.1_3 and <6.1.1_4 allows a local unprivileged user with write access to a shared directory to swap a symbolic link in place of a lock directory between a check and subsequent operations. This can cause the lock user's process to create claim files in an attacker-chosen directory, potentially disrupting other locks and causing denial of service until manually resolved.
A vulnerability in filelock versions 4.1.0 through 4.2.0 allows a local user with write permission on the directory holding the lock database to rename directories and cause the lock user's process to recursively delete arbitrary directories. This occurs because the ReadWriteLock and AsyncReadWriteLock implementations remove private .filelock-* link directories without verifying that the path still points to the originally created directory. The issue affects macOS since version 4.1.1 and POSIX environments without a usable /proc/self/fd, such as chroots or containers without /proc mounted. The vulnerability has a CVSS score of 6.1 (Medium) and results in high integrity impact by enabling deletion of directories owned by the lock user without error reporting.
A vulnerability in filelock versions 3.22.0 through 4.2.0 allows a local unprivileged user to cause two processes of the lock owner to simultaneously hold the same lock due to a race condition involving inode reuse and stale lock file breaking. This occurs on filesystems like ext4 and xfs that reuse inode numbers immediately after file deletion, combined with a sticky shared directory such as /tmp. The issue leads to high integrity impact as concurrent holders can write protected data without detection, but does not affect confidentiality or availability.
CVE-2026-112934 is a medium severity vulnerability in filelock versions >=6.1.1_3 and <6.1.1_4 used by virtualenvwrapper. It involves the SoftReadWriteLock mechanism refreshing its holder record by reopening and writing to a file without verifying the file type beyond symbolic links. A local attacker who owns the lock's .rw directory can rename a FIFO (named pipe) or a hard link over the holder record file, causing the lock user's write or read lock operations to hang or overwrite part of a private file. This leads to a denial of service by stalling lock acquisition and heartbeat threads, and can cause two processes to believe they hold the write lock simultaneously. The vulnerability requires local access and certain filesystem conditions, such as permissive hard link policies on Linux or default macOS/BSD behavior. A fix is available in version 6.1.1_4.
The filelock library's ReadWriteLock and AsyncReadWriteLock use an SQLite-backed lock database. A crafted lock database file placed by a local user at the lock path can cause every acquire operation to stall or hang indefinitely, ignoring timeout and blocking parameters. This results in a denial of service affecting availability only, without compromising confidentiality or integrity. The issue affects filelock versions 3.20.4 through 4.2.0. A fix is available in version 6.1.1_4 of the related virtualenvwrapper product.
A vulnerability in filelock versions 4.1.0 through 4.2.0 allows a local unprivileged user who can write to a shared lock directory without the sticky bit to exploit a race condition involving symbolic links and hard links. This can lead to the creation of a hard link to a file owned by the lock user, exposing file metadata and enabling the attacker to manipulate the file's name. On version 4.2.0, this can result in truncation of the lock user's file. The issue arises due to the restore branch of the stale-lock break process following symbolic links when creating hard links, which is affected by changes in CPython 3.12 and later on Linux and macOS. The vulnerability requires specific conditions including a writable non-sticky directory and repeated lock acquisition by the lock user.
A symlink swap race condition in the SoftFileLock implementation allows a local user with write access to the lock directory to leak one bit of information about whether a path exists and is writable by the lock user. This occurs because the writability check follows symlinks after an lstat call, enabling a time-of-check to time-of-use (TOCTOU) leak. The vulnerability affects filelock versions 3.32.6 through 4.2.0 and is mitigated on Linux by the fs.protected_symlinks kernel setting in sticky world-writable directories like /tmp. The impact is limited to leaking existence and writability of a chosen path, with no integrity or availability effects. The vulnerability is rated low severity with a CVSS score of 2.5 due to high attack complexity and limited information leakage.
A vulnerability in the filelock library versions >=6.1.1_3 and <6.1.1_4 allows a local unprivileged user to pre-create a protocol directory used for lock ownership state. This causes the locking mechanism to adopt a directory owned by the attacker, enabling them to interfere with lock claims and potentially cause multiple processes to enter critical sections simultaneously. The issue affects StrictSoftFileLock and SoftReadWriteLock classes, leading to integrity and availability impacts without confidentiality loss. The vulnerability requires the attacker to win initial ownership of the protocol directory before the lock user's first acquire operation, typically in shared sticky directories like /tmp. The CVSS 3.1 score is 6.3 (Medium). A fix is available in version 6.1.1_4.
UnixFileLock, used by FileLock and AsyncFileLock on Unix, truncates and can change permissions of any regular file that another local user renames or hard-links onto the lock path. This occurs when the lock user acquires the lock and the file at the lock path is unexpectedly replaced by a file controlled by another user. The vulnerability requires the attacker to have local access and the ability to rename or hard-link files in certain directory conditions. The flaw affects all filelock versions up to and including 4.2.0, with fixes available in later versions.
The vulnerability in filelock versions >=3.30.0 and <=4.2.0 involves the creation of claim directories without proper restrictive permissions, allowing other local users with write access to these directories to unlink claim files. This can lead to multiple holders believing they have exclusive locks, causing integrity issues. The flaw requires specific environment conditions such as a permissive umask or default ACLs that grant write permissions to other users. The vulnerability has a medium severity with no confidentiality impact but high integrity impact.
A vulnerability in filelock versions 4.1.0 through 4.2.0 allows a local unprivileged user to evict a lock file held by another user by exploiting inode reuse and coarse clock timestamp manipulation on ext4 or overlayfs filesystems. This causes two processes of the lock owner to enter a critical section simultaneously, violating lock integrity without affecting confidentiality or availability. The attack requires specific timing conditions and filesystem behavior, making it a high complexity local attack with medium severity.
The msgpack-python C extension has an unbounded memory leak when deserializing MessagePack data with strict_map_key validation enabled (default). If a map key is invalid, the decoded map value is leaked, causing process memory growth and potential denial of service. This affects both unpackb() and the streaming Unpacker API. Additionally, a use-after-free or double Py_DECREF issue exists in the streaming Unpacker due to stale parser-stack references after nested container parsing. The pure-Python fallback does not exhibit this leak. The issue is confirmed in msgpack version 1.2.2 and fixed in 2.10.1_2.
`SoftReadWriteLock` (and `AsyncSoftReadWriteLock`, which wraps one) checks once per lock object, by name, that `<path>.rw`, `<path>.rw/gen` and `<path>.rw/holders` are real directories and not symbolic links (files that redirect to another path). It then keeps only a boolean. Every later record operation resolves the full path again, and `O_NOFOLLOW` (a flag that makes an open fail when the final name is a symbolic link) protects the last component only. Another local user (the other user below) who can write the directory holding the lock, or who created `<path>.rw` first in a sticky directory such as `/tmp` (the sticky bit is a directory flag that lets only a file's owner rename or remove it), can put a tree under that name whose `gen` or `holders` is a symbolic link into a directory of the user running the lock (the lock user below).
A long-running process of the lock user that has already passed the check then creates, renames over and deletes files there with the lock user's privileges, including in `0700` directories the other user cannot open. The names and bytes are filelock's own lock records, not chosen by the other user. The scanner's reproducer replaces `.git/HEAD` in the lock user's private repository so that `git status` fails. There is no race. Affected versions: filelock >= 4.1.0 and <= 4.2.0. Anthropic's OSS Scanner reported it in private as `ANT-2026-WXXRI4M4` [high, CWE-367], titled "SoftReadWriteLock follows gen dir swapped for a symlink after first acquire".
## Severity
**CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N, 3.3 (Low).**
`AV:L` (local): the other user needs an account on the same host. `AC:L` (low attack complexity): the swap happens between two acquisitions, with no race to win. `PR:L` (low privileges): a local user with ordinary privileges is enough. `UI:N` (no user interaction): the lock user's process acts on its own. `C:N` (no confidentiality impact): the other user learns nothing. `I:L` (low integrity impact): the lock user's process replaces a file named `HEAD`, creates `epoch` and generation records, and deletes files whose names match the protocol's patterns, in any directory the lock user can write, with the lock user's privileges. The other user does not choose the bytes, but the files are gone and the chosen directory (a git repository) stops working. `A:N` (no availability impact): the lock itself keeps working and the lock user's process does not stall. The scanner rated it high; we scored the vector for a lock user with ordinary privileges.
Classification from the external review: conditional security. It is a cross-user replacement of a cached `.rw` tree that redirects later writes of the lock user through an intermediate symbolic link. It needs a planted tree in sticky `/tmp` or a writable parent without the sticky bit. Scoring note: we rate integrity low rather than high. The bytes written through the swapped tree are filelock's own records, not content the other user chose, so the lower reading of the CVSS integrity metric applies.
## Scope and preconditions
- Trust boundary: the other party is a different local account with write access to the lock's parent directory. Without the sticky bit (a `0777` scratch or spool directory, or a group-writable project or cache directory shared with that account's group) write access alone is enough. The other user renames the lock user's own `0700` `<path>.rw` aside and puts its tree in place. In a sticky parent such as `/tmp` the extra precondition is that it created `<path>.rw` (with real `gen` and `holders` directories, mode `0777`) before the lock user's first acquire. `prepare()` accepts an existing tree whoever owns it, and the other user later replaces its own `gen` with a symbolic link. `fs.protected_symlinks=1` (a Linux setting that refuses to follow another user's symbolic link in a world-writable sticky directory) does not intervene, because the link sits inside the other user's own non-sticky `<path>.rw`, not in the sticky parent (the scanner ran with that setting).
- Lock user: any process that keeps one `SoftReadWriteLock` or `AsyncSoftReadWriteLock` object (a singleton per path by default) and acquires it more than once, or is waiting for it when the swap happens. A fresh process that meets the planted tree gets `RuntimeError`. Between two acquisitions there is no timing to win.
- Targets: any directory the lock user can write, on any filesystem. The other user needs only to know its path (`/home/victim/project/.git` in the reproducer, under a `0700` home directory the other user cannot open).
- Platform: observed on Linux. The code path is the same on every POSIX platform and on Windows, where a junction (a Windows directory that points at another directory) at a directory component plays the symbolic link's part. The scanner ran Linux only.
- Ancestor boundary: protection against another local user is possible only while no other user can replace the lock's directory or any of its ancestors. That
CVE-2026-112940 affects the ReadWriteLock and AsyncReadWriteLock components of filelock versions 3.20.4 through 4.2.0, where SQLite reopens lock databases by name following symlinks and acting on side files such as -journal, -wal, and -shm. This behavior allows a local attacker with write access to the directory containing the lock database (if it is world- or group-writable without the sticky bit) to manipulate lock operations, causing the lock user to write attacker-controlled data into their own files, create or unlink files, or cause lock acquisition failures. The vulnerability requires local access and specific directory permissions. The issue is fixed in filelock version 2.10.1_3.
`SoftFileLock`, `MarkerSoftFileLock`, `SoftFileLease`, their async variants and a `FileLock` that has fallen back to a soft lock on `ENOSYS` decide from the record inside the marker file whether its owner is gone. The marker is the file whose presence says a process holds the lock. They do not check who could have written that record.
A local user who can write the marker but cannot remove it rewrites the holder's record to name a dead PID (process id). That position arises with an explicit `mode` with group or other write bits, or the default mode under a lax umask (the process setting that strips permission bits from new files), in a sticky or otherwise non-removable directory. The sticky bit is a directory flag that lets only a file's owner remove or rename it. The next contender running as the holder's account, or root, judges the lock stale, removes the live marker on that user's behalf and acquires it. Two processes then run the critical section together and neither gets an error. Affected versions are filelock 3.22.0 through 4.2.0 (finding `ANT-2026-W1H9NXUH`).
## Severity
**CVSS 3.1 `CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N` scores 4.7 (Medium).** `AV:L` (local): the other user needs an account on the same host. `PR:L` (low privileges): an ordinary account is enough. `UI:N` (no user interaction). `AC:H` (high attack complexity): the marker must carry group or other write bits (an explicit permissive `mode`, or umask `002`/`000` with a shared group), and a contender of the holder's account must ask for the lock while the forged record is in place. `I:H` (high integrity impact): two holders then write whatever the lock protects, and the holder is not told. `C:N` and `A:N` (no confidentiality or availability impact). `S:U` (scope unchanged). Classification from the review: **security, conditional** on another user being able to write the live marker. The scanner rated it high (CWE-345). The default mode under umask `022` is not affected.
## Scope and preconditions
- The other user can write the marker. The application passes a `mode` with group or other write bits, which `fchmod` applies as given since 4.1.0. `0o666` is a common choice for a lock shared between accounts, although a soft-lock contender of another account waits as well on a `0o644` marker, since contenders only read and rename. Or the application uses the default mode (`0o666` through the umask) under umask `002` in a directory whose group the other user belongs to, or under umask `000`. The default mode under umask `022` is not affected.
- The other user cannot remove the marker itself: the directory is sticky, or the other user cannot write it at all (a `0755` directory owned by the lock's user gives the same overlap). In a non-sticky shared directory the other user can unlink the marker without filelock, and filelock adds nothing.
- A contender that may rename the marker asks for the lock: another process of the holder's account (several workers of one user) or root. A contender of another unprivileged account cannot rename the marker in a sticky directory and times out.
- The finding reaches every class that publishes a soft marker: `SoftFileLock`, `MarkerSoftFileLock`, `SoftFileLease`, their async variants, and `FileLock(mode=0o666)` on a filesystem where `flock` (a kernel lock on an open file) fails with `ENOSYS`.
These protections against another local user hold only when no other user can replace the lock's directory or any of its ancestors. That holds when each ancestor belongs to the user or root and is either not writable by others or sticky. A user who can rename entries in a non-sticky directory above the lock controls every name below it, which no file-based lock can defend against.
## Affected code
At the scanned commit b831496: the create mode in [`SoftFileLock._acquire`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft.py#L67-L71), the explicit-mode `fchmod` in [`_apply_explicit_mode`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft.py#L100-L105), the trusting verdict in [`_try_break_stale_lock`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft.py#L107-L123) and the [`owner_is_stale`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_identity.py#L64-L79) it relies on; the same call in [`MarkerSoftFileLock`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_marker.py#L74-L81) and [`SoftFileLease`](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_lease.py#L229-L256).
## Introduced
The stale verdict that trusts the record came in with e35c3afac473 ("feat(soft): detect and break stale locks", #476, 2026-02-13), first released in 3.22.0. From then on a marker left group- or other-writable by the umask is forgeable. The re
### Summary
`ReadWriteLock` and `AsyncReadWriteLock` resolve the lock path with `pathlib.Path.resolve()` and pass it to `sqlite3.connect()` without refusing a symlink. A local user who can create names in the lock's directory, such as `/tmp` or a shared cache, can plant a symlink at the lock path and make the victim's process create, lock, or write the file it points to, or break mutual exclusion between the victim's own processes.
### Details
`ReadWriteLock.__init__` stores `pathlib.Path(lock_file).resolve()`, which follows a final symlink, and every connection opens that path through `sqlite3.connect()` with no `O_NOFOLLOW` or regular-file check. SQLite's own VFS also resolves the final symlink in user space, so `fs.protected_symlinks` and the sticky bit do not help: the kernel never sees a symlink to refuse. The other lock classes do not follow a final symlink: `FileLock` opens with `O_NOFOLLOW`, and `SoftReadWriteLock` coordinates through `<path>.rw/`.
### Proof of concept
On Linux, with the victim and attacker as different users and `/shared` mode 1777 with `fs.protected_symlinks=1`:
1. The attacker runs `ln -s /home/victim/private/pwned.flag /shared/app.rwlock.db`.
2. The victim constructs `ReadWriteLock("/shared/app.rwlock.db")`. A plain `os.open(..., O_NOFOLLOW)` on the same path fails, but the lock creates `/home/victim/private/pwned.flag`, owned by the victim, inside a directory the attacker cannot write.
3. With `/shared/cache.rwlock.db -> /shared/a.db`, one victim process holds the write lock. The attacker repoints the link to `/shared/b.db`, and a second victim process acquires the write lock while the first still holds it.
The same behavior reproduces on macOS, on Windows 11, and through `AsyncReadWriteLock`.
### Impact
A local attacker with write access to the lock directory can make the victim create empty files it owns at paths the attacker cannot write, make the victim hold a SQLite lock on another application's database so that application gets `database is locked`, and give two victim processes the write lock at once, letting them corrupt the resource the lock protects.
### Workarounds
Keep `ReadWriteLock` paths in directories that only trusted users can write.