VulnWatch VulnWatch
← Back to dashboard
Medium github · GHSA-6627-m3xw-93mp

filelock: StrictSoftFileLock creates its claim directories without the lock mode, so another local user with a write bit on them can end a live hold

Published Oct 28, 2026 CVSS 5.3

StrictSoftFileLock and AsyncStrictSoftFileLock apply the caller's mode to the sentinel (the lock file at ``) and to both claim files (the files whose presence says a process wants or holds the lock). They create the two directories that hold the claims, .filelock and .filelock/claims, with a bare mkdir(). That gives 0o777 filtered through the umask (a per-process mask that removes permission bits from new files and directories) or, under a parent with a default ACL (an access control list on a directory that sets the permissions of entries created inside it), through that ACL.

A hold consists of two claim names in that directory, which has no sticky bit (a directory flag that lets only a file's owner remove it). When the environment leaves another local user (the other user below) a write bit on the directory, that user can unlink the holder's 0600 claims. Three settings do this: umask 000 in a sticky directory such as /tmp, umask 002 with the other user in the directory's group, or a default ACL on the lock's parent that grants the group write (the kernel then ignores the umask). After the unlink, the next contender of the holder's account finds the directory empty and enters. The first holder keeps reporting is_locked == True and later releases with no error. Affected versions: filelock >= 3.30.0 and >D: mkdir() both directories: 0777, claims 0600 H->>D: publish intent and held claims, enter X->>D: read claim: EACCES (0600) rect rgb(255, 214, 214) X->>D: unlink both claims (directory is 0777, not sticky) C->>D: acquire(): scan finds no claims, publishes, enters Note over H,C: both inside at once H->>D: release(): claims missing, counted as removed, exit status 0 end Note over H,D: control under umask 022: directories 0755, unlink denied, contender raises Timeout


## Evidence

The scanner's reproducer runs the holder's `StrictSoftFileLock(path, mode=0o600)` with `timeout=2` as account `victim` (uid 1000) and the unlink loop as account `attacker` (uid 1001). Both run in a fresh root-owned `1777` directory under `/tmp`, at commit b831496 on Linux 6.1 (overlayfs), CPython 3.14.8. Two rounds differ only in the umask the holder's processes start with.

Under `CONTROL umask 022`, the directories are `0755`, the kernel denies the unlinks, both claims remain, and the second process prints `Timeout`. Under `OBSERVED umask 000`, every file is still `0600` but `.filelock` and `claims/` are `0777`. The other account prints `unlinked held-v1-.claim` and `unlinked intent-v1-.claim` followed by `claims left: 0`. The second process prints `entered`. The first process prints `leaving, is_locked=True, exit status 0` when asked afterwards. The verdict lines read `CONTROL two holders at once: False` and `OBSERVED two holders at once: True`; the overall verdict is `BUG`. The scanner ran the umask `002` and default-ACL rows of the table by hand at the same commit with the same result.

Our review ran the reproducer against the 4.2.0 release image and the scanned commit (`BUG` on both) and against the head of #839 (`OK`). The review's regression test covers the owner, group-read and group-write modes.

## Impact

Another local user who gets a write bit on the claim directories ends a live `StrictSoftFileLock` hold. A second honest process of the holder's account then enters the critical section beside the first. Neither holder receives any signal. This is the overlap the strict lock's fail-closed contract exists to rule out. The same write access lets the other user deny the lock by planting a malformed claim name. This does not disclose the claims' contents (the `0600` claim files stay unreadable), and it does not affect holders whose directories came out `0755` or tighter.

## Workarounds

Run processes that take strict locks with umask `022` or `077`. Do not put a default ACL that grants other accounts write on the lock's parent directory; where you intend group sharing, trust every member of that group with the lock. Keep strict locks in a directory other users cannot write. For paths already in use, `chmod 700` (or remove, while no process holds the lock) every existing `.filelock` tree. Its mode comes from creation time and nothing changes it afterwards: `find  -maxdepth 1 -type d -name '*.filelock' -exec chmod -R go-w {} +`.

## Patched version

4.2.1.

Fix: https://github.com/tox-dev/filelock/pull/839

## Credits

Reported by Anthropic's OSS Scanner (automated analysis), 15 October 2026; reviewed by the maintainers.

- 2026-10-15 23:08 UTC: report received (finding `ANT-2026-AD6SUOON`, scanned commit b831496b0273)
- 2026-10-16 01:31 UTC: fix PR #839 opened
- 2026-10-16 05:39 UTC: draft advisory created (first as part of GHSA-9c4x-gm8v-wgc4, then split into this advisory)

Affected AI Products

anthropic
Get the weekly digest. Every Monday: top AI security stories of the week. Free.