filelock Time-of-Check-Time-of-Use (TOCTOU) Symlink Vulnerability in SoftFileLock
Description
filelock is a platform-independent file lock for Python. Prior to version 3.20.3, a TOCTOU race condition vulnerability exists in the SoftFileLock implementation of the filelock package. An attacker with local filesystem access and permission to create symlinks can exploit a race condition between the permission validation and file creation to cause lock operations to fail or behave unexpectedly. The vulnerability occurs in the _acquire() method between raise_on_not_writable_file() (permission check) and os.open() (file creation). During this race window, an attacker can create a symlink at the lock file path, potentially causing the lock to operate on an unintended target file or leading to denial of service. This issue has been patched in version 3.20.3.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
filelockPyPI | < 3.20.3 | 3.20.3 |
Affected products
1Patches
241b42dd2c72aFix TOCTOU symlink vulnerability in SoftFileLock (#465)
2 files changed · +19 −1
docs/index.rst+16 −0 modified@@ -216,6 +216,22 @@ The :class:`SoftFileLock <filelock.SoftFileLock>` only watches the existence of portable, but also more prone to dead locks if the application crashes. You can simply delete the lock file in such cases. +.. warning:: + + **Security Consideration - TOCTOU Vulnerability**: On platforms without ``O_NOFOLLOW`` support + (such as GraalPy), :class:`SoftFileLock <filelock.SoftFileLock>` may be vulnerable to symlink-based + Time-of-Check-Time-of-Use (TOCTOU) attacks. An attacker with local filesystem access could create + a symlink at the lock file path during the small race window between permission validation and file + creation. + + On most modern platforms with ``O_NOFOLLOW`` support, this vulnerability is mitigated by refusing + to follow symlinks when creating the lock file. + + For security-sensitive applications, prefer :class:`UnixFileLock <filelock.UnixFileLock>` or + :class:`WindowsFileLock <filelock.WindowsFileLock>` which provide stronger guarantees via OS-level + file locking. :class:`SoftFileLock <filelock.SoftFileLock>` should only be used as a fallback mechanism + on platforms where OS-level locking primitives are unavailable. + Asyncio support ---------------
src/filelock/_soft.py+3 −1 modified@@ -16,13 +16,15 @@ class SoftFileLock(BaseFileLock): def _acquire(self) -> None: raise_on_not_writable_file(self.lock_file) ensure_directory_exists(self.lock_file) - # first check for exists and read-only mode as the open will mask this case as EEXIST flags = ( os.O_WRONLY # open for writing only | os.O_CREAT | os.O_EXCL # together with above raise EEXIST if the file specified by filename exists | os.O_TRUNC # truncate the file to zero byte ) + o_nofollow = getattr(os, "O_NOFOLLOW", None) + if o_nofollow is not None: + flags |= o_nofollow try: file_handler = os.open(self.lock_file, flags, self._context.mode) except OSError as exception: # re-raise unless expected exception
255ed068bc85Fix TOCTOU symlink vulnerability in SoftFileLock
2 files changed · +19 −1
docs/index.rst+16 −0 modified@@ -216,6 +216,22 @@ The :class:`SoftFileLock <filelock.SoftFileLock>` only watches the existence of portable, but also more prone to dead locks if the application crashes. You can simply delete the lock file in such cases. +.. warning:: + + **Security Consideration - TOCTOU Vulnerability**: On platforms without ``O_NOFOLLOW`` support + (such as GraalPy), :class:`SoftFileLock <filelock.SoftFileLock>` may be vulnerable to symlink-based + Time-of-Check-Time-of-Use (TOCTOU) attacks. An attacker with local filesystem access could create + a symlink at the lock file path during the small race window between permission validation and file + creation. + + On most modern platforms with ``O_NOFOLLOW`` support, this vulnerability is mitigated by refusing + to follow symlinks when creating the lock file. + + For security-sensitive applications, prefer :class:`UnixFileLock <filelock.UnixFileLock>` or + :class:`WindowsFileLock <filelock.WindowsFileLock>` which provide stronger guarantees via OS-level + file locking. :class:`SoftFileLock <filelock.SoftFileLock>` should only be used as a fallback mechanism + on platforms where OS-level locking primitives are unavailable. + Asyncio support ---------------
src/filelock/_soft.py+3 −1 modified@@ -16,13 +16,15 @@ class SoftFileLock(BaseFileLock): def _acquire(self) -> None: raise_on_not_writable_file(self.lock_file) ensure_directory_exists(self.lock_file) - # first check for exists and read-only mode as the open will mask this case as EEXIST flags = ( os.O_WRONLY # open for writing only | os.O_CREAT | os.O_EXCL # together with above raise EEXIST if the file specified by filename exists | os.O_TRUNC # truncate the file to zero byte ) + o_nofollow = getattr(os, "O_NOFOLLOW", None) + if o_nofollow is not None: + flags |= o_nofollow try: file_handler = os.open(self.lock_file, flags, self._context.mode) except OSError as exception: # re-raise unless expected exception
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-qmgc-5h2g-mvrwghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-22701ghsaADVISORY
- github.com/tox-dev/filelock/commit/255ed068bc85d1ef406e50a135e1459170dd1bf0ghsax_refsource_MISCWEB
- github.com/tox-dev/filelock/commit/41b42dd2c72aecf7da83dbda5903b8087dddc4d5ghsax_refsource_MISCWEB
- github.com/tox-dev/filelock/security/advisories/GHSA-qmgc-5h2g-mvrwghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.