filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a
Affects filelockSource GCVE Database
Not known to be exploited · CVSS 5.8 Medium : upgrade to 4.2.1 when convenient.
Data as of 28 Oct 2026, 22:12 UTC
- Patch
- Available – fixed in 4.2.1
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:HExploitation evidence
Disclosed: evidence found.
CVE published 28 Oct 2026
Detectable: no evidence on record.
No public nuclei template indexed
Weaponised: no evidence on record.
No public exploit code indexed in Metasploit or Exploit-DB
Exploited in the wildExploited: no evidence on record.
Not in CISA KEV and no source reports exploitation
Observed by OffSeq MirageSeen by Mirage: no evidence on record.
No attack traffic recorded by OffSeq Mirage sensors
A missing step is not evidence of safety. Sources: cve.org (opens in a new tab), the Metasploit, Exploit-DB and nuclei-templates index as of 26 Oct 2026.
What to do
Upgrade filelock to 4.2.1.
Affected software
| Product | Affected | Fixed in |
|---|---|---|
| PyPIfilelock | Affected
| Fixed in
|
Check your own hosts for these packages with threat-finder (opens in a new tab), our free open-source scanner.
Description
`StrictSoftFileLock` and `AsyncStrictSoftFileLock` check `<path>.filelock` (the coordination directory that holds the lock's state) with one `lstat` call on its name. `lstat` reports what a name is without following a symbolic link (a file that redirects to another path). After that check, the code reaches `<path>.filelock/claims` by pathname for every later operation (`mkdir`, scan, publish, link, unlink). `_open_directory` passes `O_NOFOLLOW` (a flag that makes an open fail when the final name is a symbolic link), but the flag covers only the final `claims` component. The kernel follows a symbolic link in any earlier component. Another local user (the other user below) who can rename `<path>.filelock` exchanges it for a symbolic link after the check. In a shared directory without the sticky bit (a directory flag that lets only a file's owner rename or remove it), any user with write access can do this. Where the shared directory is sticky, such as `/tmp`, only the user who created `<path>.filelock` before the user running the lock (the lock user below) first used it can. The lock user's process (root's, if root takes the lock) then creates a `claims` directory and claim files (the files whose presence says a process wants or holds the lock) inside a directory the other user chooses but only the lock user can write. When the link points at another strict lock's `.filelock` directory, the stranded claims make that lock time out for every process until an operator finds and force-breaks each one. The `claims` property and `force_break()` resolve the same path with no check at all. Affected versions: filelock >= 3.30.0 and <= 4.2.0 (finding `ANT-2026-SVFEYX89`). ## Severity **CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H, 5.8 (Medium).** `AV:L` (local): the other user needs an account on the same host. `AC:H` (high attack complexity): the swap must land between the `lstat` and the next `mkdir`. The other user does not aim at that window. It flips the name in a loop with `renameat2(RENAME_EXCHANGE)` (a system call that swaps two names in one step) across repeated acquires, and won after 1 to 31 runs of the lock user's program in the scanner's trials. A sticky directory also requires it to have created `<path>.filelock` first. `PR:L` (low privileges): an unprivileged account is enough. `UI:N` (no user interaction): the lock user's process acts on its own. `C:L` (low confidentiality impact): through `claims`, one file name per planted link from a directory only the lock user can list. `I:L` (low integrity impact): a directory named `claims` and files with filelock's fixed claim names and contents appear, created with the lock user's privileges, in a directory the other user chooses but cannot write. The process overwrites or truncates nothing that exists. `A:H` (high availability impact): aimed at another strict lock of the lock user, the stranded claims deny that lock to every process until an operator finds and force-breaks each one. Classification from the review: security, conditional on the other user being able to rename the intermediate component. The scanner rated it high (CWE-363). ## Scope and preconditions - The other user can rename `<path>.filelock`. In a writable directory without the sticky bit (a `0777` or group-writable project or cache directory), any user with write permission on the directory can, even though the lock user created and owns `<path>.filelock`. In a sticky directory such as `/tmp`, only the user who created `<path>.filelock` before the lock user's first use can, because that user then owns both the directory and the symbolic link (the planting precondition of GHSA-9c4x-gm8v-wgc4). - The link's target is a directory the lock user can write. The effect that matters is on that directory. An acquire that completes through the link also holds the shared lock with its claims elsewhere, but a user who can rename `<path>.filelock` can defeat that lock's exclusion anyway. - `fs.protected_symlinks=1` (a Linux setting that refuses to follow another user's symbolic link in a world-writable sticky directory) does not interfere. The link is an intermediate path component, not the last one. In the sticky-directory case it also sits in a directory the other user owns. - Missed attempts show up to the lock user as `SoftFileLockProtocolError` or `FileNotFoundError`. The swap therefore works against a lock that a program takes more than once: a periodic job, a worker pool, or a caller that retries or waits with a timeout (each poll of a waiting acquisition is a new attempt). - The two entry points that need no race (`claims` and `force_break()` on a resting symbolic link) depend on the lock user inspecting or recovering the lock. The planted link invites this by making `acquire()` fail with a protocol error. The `force_break()` variant works only when the lock user breaks claims that name a live process on its own host without checking them first, as the recovery loop in `docs/tutorials.rst
References
- github.com/tox-dev/filelock/security/advisories/GHSA-m462-7rxw-wvpg (opens in a new tab)
- github.com/tox-dev/filelock/pull/839 (opens in a new tab)
- github.com/tox-dev/filelock/commit/bfa066d65a1ba9106f86ee9d027f7588b9c77e03 (opens in a new tab)
- github.com/tox-dev/filelock (opens in a new tab)
- github.com/tox-dev/filelock/releases/tag/4.2.1 (opens in a new tab)