CVE-2026-112938
filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a directory another local user chooses
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- High
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- Low
- Integrity
- Low
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
5.8
filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a directory another local user chooses
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
CVE-2026-112938- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Weakness
- CWE-363
- Updated
- 2026-11-05
EUVDEUVD-2026-117814
5.8
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
EUVD-2026-117814- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Updated
- 2026-11-06
GitHub AdvisoriesGHSA-m462-7rxw-wvpg
5.8
filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a directory another local user chooses
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 (a0777or 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>.filelockbefore 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>.filelockcan defeat that lock's exclusion anyway. fs.protected_symlinks=1…
- Record
GHSA-m462-7rxw-wvpg- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Weakness
- CWE-363
- Updated
- 2026-11-02
NVD
5.8
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
CVE-2026-112938- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Weakness
- CWE-363
- Updated
- 2026-11-07
OSV
5.8
filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a directory another local user chooses
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
CVE-2026-112938- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Weakness
- CWE-363
- Updated
- 2026-11-07
OSVDEBIAN-CVE-2026-112938
5.8
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
DEBIAN-CVE-2026-112938- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Updated
- 2026-11-07
OSVGHSA-m462-7rxw-wvpg
5.8
filelock: StrictSoftFileLock follows a symbolic link swapped in at <path>.filelock and creates claim files in a directory another local user chooses
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 (a0777or 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>.filelockbefore 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>.filelockcan defeat that lock's exclusion anyway. fs.protected_symlinks=1…
- Record
GHSA-m462-7rxw-wvpg- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Weakness
- CWE-363
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-112938
5.8
filelock is a platform-independent file lock for Python. From 3.30.0 until 4.2.1, On POSIX platforms, StrictSoftFileLock and AsyncStrictSoftFileLock validate the coordination directory in _ensure_protocol_directory but later reach the claims directory through _open_directory by pathname, allowing a local account that can rename the coordination name to swap in a symbolic link between check and use during acquisition. That race can create and leave claim files in another writable directory or strand claims in a different strict lock so the second lock times out. Separately, the claims property and force_break follow a resting symbolic link without a race when the lock user inspects or recovers the lock. Claims inspection discloses a file name to the other account only if the resulting exception text or claim_name reaches that account through a shared log, CI output, or error report. A blind force_break recovery that removes live claims from another strict lock can allow two processes into that lock's critical section; this path reaches other strict locks, not arbitrary files. This issue is fixed in version 4.2.1.
- Record
UBUNTU-CVE-2026-112938- CVSS 3.1
- 5.8 Medium
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:H - Updated
- 2026-11-07
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
filelockPyPI |
3.30.0 to 4.2.0 | 4.2.1 |
python-filelockDebian:12 |
All versions, plus listed versions 3.12.2-13.12.3-13.12.4-13.13.1-13.13.3-1 Show 30 moreShow less3.13.4-13.14.0-13.15.4-13.16.1-13.16.1-23.17.0-13.18.0-13.19.1-13.20.0-13.20.2-13.20.3-13.24.3-13.25.0-13.25.2-13.29.0-13.29.4-13.29.5-13.29.7-13.32.0-13.32.2-13.32.4-13.32.4-23.32.5-13.32.6-13.9.0-13.9.0-1+deb12u14.0.1-14.0.12-14.1.1-14.2.8-1 |
None known |
python-filelockDebian:13 |
All versions, plus listed versions 3.18.0-13.18.0-1+deb13u13.19.1-13.20.0-13.20.2-1 Show 18 moreShow less3.20.3-13.24.3-13.25.0-13.25.2-13.29.0-13.29.4-13.29.5-13.29.7-13.32.0-13.32.2-13.32.4-13.32.4-23.32.5-13.32.6-14.0.1-14.0.12-14.1.1-14.2.8-1 |
None known |
python-filelockDebian:14 |
All versions, plus listed versions 3.18.0-13.19.1-13.20.0-13.20.2-13.20.3-1 Show 17 moreShow less3.24.3-13.25.0-13.25.2-13.29.0-13.29.4-13.29.5-13.29.7-13.32.0-13.32.2-13.32.4-13.32.4-23.32.5-13.32.6-14.0.1-14.0.12-14.1.1-14.2.8-1 |
None known |
filelockPyPI |
3.30.0 up to 4.2.1, plus listed versions 3.30.13.30.23.30.33.31.03.31.1 Show 25 moreShow less3.31.23.32.03.32.23.32.33.32.43.32.53.32.63.32.74.0.04.0.14.0.104.0.114.0.124.0.24.0.34.0.44.0.54.0.64.0.74.0.84.0.94.1.04.1.14.1.24.2.0 |
4.2.1 |
python-filelockUbuntu:Pro:18.04:LTS |
All versions, plus listed versions 2.0.11-12.0.12-12.0.13-13.0.0-23.0.3-13.0.4-13.0.4-1ubuntu0.1~esm1 |
None known |
python-filelockUbuntu:Pro:20.04:LTS |
All versions, plus listed versions 3.0.12-13.0.12-23.0.12-2ubuntu0.1~esm1 |
None known |
python-filelockUbuntu:Pro:22.04:LTS |
All versions, plus listed versions 3.0.12-23.3.2-13.4.0-13.4.2-13.4.2-23.6.0-13.6.0-1ubuntu0.1~esm1 |
None known |
python-filelockUbuntu:Pro:24.04:LTS |
All versions, plus listed versions 3.12.2-13.12.4-13.13.1-13.13.1-1ubuntu0.1~esm1 |
None known |
python-filelockUbuntu:26.10 |
All versions, plus listed versions 3.20.3-13.29.4-13.32.0-13.32.2-1 |
None known |
python-filelockUbuntu:26.04:LTS |
All versions, plus listed versions 3.18.0-13.20.0-13.20.2-13.20.3-1 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases, references | NVD, OSV | |
| affected, aliases, references | OSV | |
| references | OSV | |
| aliases | EUVD, NVD | |
| description, facts, products, references, severity | CVE List | |
| first indexed | GitHub Advisories, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-112938 is a medium vulnerability (CVSS 5.8) in Tox-dev Filelock, published October 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.11%, the 1st percentile. Fixed in filelock 4.2.1.
References
github.com/tox-dev/filelock/security/advisories/GHSA-m462-7rxw-wvpg
github.com/tox-dev/filelock/pull/839
github.com/tox-dev/filelock/commit/aaa18595d29795fab599a69d6b184d9a505dab4b
github.com/tox-dev/filelock/commit/bfa066d65a1ba9106f86ee9d027f7588b9c77e03
github.com/tox-dev/filelock/releases/tag/4.2.1
github.com/advisories/GHSA-m462-7rxw-wvpg
Left out here: the rest of 2 source descriptions. The JSON record has them.