- The GitHub Advisory Database says filelock 3.20.4 through 4.2.0 has a flaw in ReadWriteLock and AsyncReadWriteLock, letting another local user misuse a lock request.
- File writes and deletes need a directory without the sticky bit. Even in a sticky directory such as /tmp, lock requests can fail, and some link-based effects remain.
- Teams should find affected versions, check use of the two classes, and review which shared directories hold lock files.
A check protects you only if it checks the thing you use
A safety check is worth little if it inspects one thing and the code then uses another. A newly published advisory shows this in a small Python library.
The library is filelock. Programs use it to stop two processes from touching the same resource at once. The GitHub Advisory Database published the flaw on October 23 as GHSA-v4x8-3wr5-3wq8.
The flaw sits in two classes only: ReadWriteLock and AsyncReadWriteLock. They keep their state in a SQLite database file. The advisory does not cover the common FileLock class.
The advisory says the lock verifies one file. It then hands SQLite a name that can point somewhere else.
Anthropic's OSS Scanner reported the issue privately as ANT-2026-KMJ2575J. The scanner rated it high, under CWE-363, a race-condition weakness. The advisory scores it 7.1 (High) on CVSS 3.1.
Versions 3.20.4 through 4.2.0 of filelock are affected. The symlink redirect applies from 4.0.9. The side-file variants, described below, apply from 3.20.4.
What has to be true for it to matter
The attacker needs an ordinary account on the same machine. That user must also be able to create or rename entries in the folder that holds the lock database.
The advisory describes such a folder as open to everyone or to a group, with the sticky bit off. The sticky bit is a folder setting. When it is on, users can rename or delete only their own entries.
Shared cache, build or project folders can fit this description.
Turning off the sticky bit is what enables the file-write and file-delete effects. A sticky folder is not fully safe, as a later section shows.
An outside review labelled the issue "conditional security". It accepted the mechanism but said it matters only if a second user can rename entries in the lock folder.
The scoring also records no confidentiality impact. The attacker cannot read anything through this flaw.
How the lock gets turned against its owner
On Linux, the lock opens its database file and checks it through a file descriptor. That is a number the kernel gives a process for each open file.
The lock then points SQLite at /proc/self/fd/<n>, a path that names that open file. It expects SQLite to reopen the very file it just checked.
The advisory says SQLite does not do that. It asks the kernel for the file's current path, then opens that path by name. It follows symlinks, which are files that point at other paths.
That leaves a gap. The attacker prepares a symlink named after the database, with "(deleted)" added. The kernel uses that label for a file whose folder entry has gone.
The attacker watches for the victim's open, swaps the entries, and SQLite follows the symlink. It lands on a file the attacker chose.
The scanner's reproducer redirected the first lock request in 77 of 77 runs, using Linux file-event notifications. The external review called this stronger evidence than a theoretical race. In that test, the victim's private 0600 notes file ended up holding the attacker's content.
The library's own checks miss this. They look at the descriptor, not the file SQLite actually opened. One further check runs only after the transaction has begun.
Planted files that need no race at all
SQLite also acts on side files it finds beside the database: a rollback journal, a write-ahead log and a shared-memory index. The advisory says these variants reach back to 3.20.4 and need no redirect.
In one example, the attacker plants a 46-byte journal that names a file. The victim's next read_lock() or write_lock() then returns without error. The named file, kept in a private folder of the victim, is gone.
The named file must be non-empty, and the victim must be able to read and delete it.
A sticky folder such as /tmp gives some protection, but not complete protection. A planted -wal file makes lock requests fail with a disk I/O error. The advisory says the library turns only "database is locked" into a timeout, so this error escapes at once.
The advisory also reports a link-based effect in sticky /tmp. A hard link to a victim's private 0600 file can lead to the same overwrite when fs.protected_hardlinks is set to 0.
Running the lock as root adds a further risk. SQLite sets the owner of a -wal or -shm file it opens to match the database owner. In the advisory's test, a private root file was planted as the lock's -wal side file. After root took a read lock, that file belonged to the other user.
Where the exposure is narrower
On macOS, and on Linux without /proc, the lock takes a different route using a hard link. The advisory says none of the effects above occur there.
The same outcome then needs the attacker to rename the lock's hidden .filelock-* folder inside a parent without the sticky bit. With the sticky bit on, that rename fails.
The advisory's own check shows the reproducer printing OK on the head of PR #834. All 20 victim runs exited cleanly. The text we reviewed does not name a released fixed version. Check the advisory for current status.
The lesson: trust follows the name, not the check
Security engineers call this pattern a confused deputy. A trusted process lends its authority to someone who has none. The attacker never gains the victim's privileges. The victim's own lock call does the damage.
That decides who pays. The cost falls on whoever runs the lock: a build account, a service or root. The person who planted the file loses nothing.
What to ask your team
Start with an inventory. Which systems run filelock 3.20.4 through 4.2.0, and does any code call either lock class? The advisory covers only those two.
Next, ask where lock database files live. A folder several accounts can write to, with the sticky bit off, exposes file writes and deletes. A sticky folder such as /tmp can still see failing lock requests and, with fs.protected_hardlinks at 0, some link-based overwrites. A folder only the lock user can write to does not meet the advisory's condition.
Then ask whether any root or service account takes locks in shared locations. The advisory's ownership example involved root.
A lock is a promise about one file. Here the check used the file's number, but the use followed its name.
Produced by the WebPulse Newsroom with AI assistance from the original reporting credited below, and checked against that source by our editorial review. How we use AI.
Original reporting: GitHub Advisory Database.





