KEVWire

Security intelligence, with context.

Response snapshot Oct 29, 2026, 01:26 UTC

Back to the wire
Permalink
VulnerabilityCVE-2026-112934

filelock: SoftReadWriteLock holder refresh writes through a hard link and hangs on a named pipe that another local user renames over its record

SoftReadWriteLock (and AsyncSoftReadWriteLock, which wraps one) refreshes its holder record (the file under .rw/holders/ that says a process holds or wants the lock) on every poll of a waiting acquire and on every heartbeat (the periodic refresh a holder runs to keep its record fresh).

At a glance

Exploited
Not known
Severity
6.1 Medium (CVSS 3.1)
Chance of exploitation
Not estimated
Sources
1 source

What to do

GitHub lists first patched versions: filelock: 4.2.1. Confirm the affected range and upgrade guidance in the exact advisory.

Read GitHub-reviewed advisory GHSA-fj95-fr6c-h845 (opens a new tab)

What happened

SoftReadWriteLock (and AsyncSoftReadWriteLock, which wraps one) refreshes its holder record (the file under .rw/holders/ that says a process holds or wants the lock) on every poll of a waiting acquire and on every heartbeat (the periodic refresh a holder runs to keep its record fresh). It does so by reopening .

rw/holders/ by name with a plain blocking O_WRONLY | O_NOFOLLOW open and writing at offset 0, without checking what it opened. O_NOFOLLOW makes the open fail only when the final name is a symbolic link (a file that redirects to another path).

A different local user (the other user below) who owns the lock's .rw tree reads the token of the user running the lock (the lock user below) from the holders/ listing and renames another node over the record. The other user owns the tree because it created it first in a sticky directory such as /tmp (the sticky bit is a directory flag that lets only a file's owner rename or remove it), or because it can write a lock directory without the sticky bit.

A FIFO (a named pipe: a file whose open for writing blocks until some process opens it for reading) makes the lock user's write_lock() / read_lock() hang regardless of timeout. It also stops a lock holder's heartbeat thread without on_compromise (the callback that tells a holder it lost the lock) ever running, so the lock grants a second process while the first still believes it holds it. This works on a default Linux.

Continue reading

Where the kernel lets a user hard-link a file it does not own (a hard link is a second name for the same file; Linux with fs.protected_hardlinks=0; macOS and the BSDs by their defaults, not executed), a hard link makes the lock user overwrite the first ~135 bytes of one of its own private files with its holder record. Affected versions: filelock >= 4.0.0 and .

rw (with gen/ and holders/) before the lock's first use in a sticky directory such as /tmp, where prepare() adopts an existing tree whoever owns it and whatever its mode. Or the lock lives in a directory without the sticky bit that the account can write (the scanner checked a root-created 0777 directory).

There being first is not needed, because the other user renames the lock user's own 0700 tree aside and puts its own in place; prepare() does not run again for a live lock object, and a waiting lock user recreates its record in the replacement. A tree the lock user already created in a sticky directory (mode 0700`) is out of reach. - FIFO variant: needs only that boundary. It works on a default Linux. fs.

protected_hardlinks plays no part, and fs.protected_fifos=1 (a Linux setting that refuses some opens of FIFOs in sticky world-writable directories) does not help, since it covers O_CREAT opens in sticky directories only, and the other user renames the FIFO into place inside its own holders/. - Hard-link variant: also needs a kernel that permits a hard link to a file the caller does not own. That is Linux with fs.

protected_hardlinks=0 (the kernel's built-in value; observed), while most distributions and the scanner's test image boot with 1, under which the other user's link() fails with EPERM (operation not permitted) and the file stays untouched. macOS and the BSDs have no such restriction by default; that follows from their link(2) semantics, and the scanner did not execute it.

The target must be a regular file the lock user may write, on the same filesystem as the lock, in a directory the other user can search. A 0600 file in a 0755 home directory qualifies; a file under a 0700 directory does not. - Platform: observed on Linux 6.1. AsyncSoftReadWriteLock runs the same code through an executor thread and loses that thread (from the code, not run).

On Windows named pipes cannot live in a regular directory, so there is no FIFO case there. - Ancestor boundary: protection against another local user is possible only while no other user can replace the lock's directory or any of its ancestors. That is the case when each ancestor belongs to the lock user or root and is either not writable by others or sticky.

Affected code

At the scanned commit b831496b0273, [OsFiles.overwrite opens by name with O_WRONLY | O_NOFOLLOW and writes without fstat](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_storage.py#L94-L100) (fstat would report the type of the file behind the open descriptor), while [read just above it uses O_NONBLOCK and a regular-file check](https://github.

com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_storage.py#L36-L43). The blocking open is [_attempt_open](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_storage.py#L156-L160) via [_open](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_storage.py#L143).

[prepare adopts an existing tree whoever owns it](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_storage.py#L121-L133). The single caller is [Participant._refresh_nonce](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_protocol.py#L544-L545), reached from [_keep_claim_fresh](https://github.

com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_protocol.py#L487-L496) on every poll of a waiting acquire and from [heartbeat](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_protocol.py#L547-L560), which knows only lost and transient, not a call that does not return.

The acquire loop checks its deadline and the _closed flag only after advance() returns ([_sync.py lines 584–592](https://github.com/tox-dev/filelock/blob/b831496b0273ecd11bf02b8d080ca8b673a538c1/src/filelock/_soft_rw/_sync.py#L584-L592)). The cod

Affected package ranges reported by GitHub: filelock: >= 4.0.0, <= 4.2.0

Scores and how they were measured

CVSS base severity

6.1

Version 3.1As of

CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H

Measurement source (opens a new tab)

How bad it is if exploited. Not a prediction of exploitation or proof you are exposed.

EPSS probability

Not available

A model's estimate of exploitation in the next 30 days, not certainty or your own risk.

Related technology

Sources

  1. Primary source

    GitHub-reviewed advisory GHSA-fj95-fr6c-h845 (opens a new tab)

    The public advisory supplies the description, affected package/version ranges, and any listed CVSS metric. GitHub review is not local review.

    Published Checked

  2. Primary source

    GitHub public advisory API page (opens a new tab)

    The API page supplied GHSA-fj95-fr6c-h845, its actual identifiers, source dates, and structured metrics.

    Published Date not suppliedChecked

Cite this record

For factual claims, cite the primary sources above; cite KEVWire for its compilation, dates, and classifications.

APA

KEVWire. (2026, October 28). filelock: SoftReadWriteLock holder refresh writes through a hard link and hangs on a named pipe that another local user renames over its record (CVE-2026-112934). https://kevwire.com/record/CVE-2026-112934

MLA

"filelock: SoftReadWriteLock holder refresh writes through a hard link and hangs on a named pipe that another local user renames over its record (CVE-2026-112934)." KEVWire, 28 Oct. 2026, kevwire.com/record/CVE-2026-112934.

Chicago

KEVWire. "filelock: SoftReadWriteLock holder refresh writes through a hard link and hangs on a named pipe that another local user renames over its record (CVE-2026-112934)." Last modified October 28, 2026. https://kevwire.com/record/CVE-2026-112934.

Evidence summary (plain text)

filelock: SoftReadWriteLock holder refresh writes through a hard link and hangs on a named pipe that another local user renames over its record (Oct 28, 2026).
SoftReadWriteLock (and AsyncSoftReadWriteLock, which wraps one) refreshes its holder record (the file under  .rw/holders/ that says a process holds or wants the lock) on every poll of a waiting acquire and on every heartbeat (the periodic refresh a holder runs to keep its record fresh). It does so by reopening  .rw/holders/  by name with a plain blocking O_WRONLY | O_NOFOLLOW open and writing at offset 0, without checking what it opened. O_NOFOLLOW makes the open fail only when the final name is a symbolic link (a file that redirects to another path).
CVSS 6.1 (version 3.1; evidence as of Oct 28, 2026; https://github.com/advisories/GHSA-fj95-fr6c-h845).
Sources:
GitHub-reviewed advisory GHSA-fj95-fr6c-h845: https://github.com/advisories/GHSA-fj95-fr6c-h845
GitHub public advisory API page: https://api.github.com/advisories?type=reviewed&per_page=100&sort=updated&direction=desc
Record ID: CVE-2026-112934.
Record origin: Ingested record.
AI evidence: Not assessed.
Known exploitation: Not assessed.
Zero-day status: Not assessed. KEV membership alone does not establish zero-day status.
About this data

This record was ingested from a data source. Retrieved: Oct 29, 2026, 00:55 UTC. Ingestion is not an independent editorial investigation.

A CISA KEV listing documents known exploitation, not necessarily a zero-day; absence from the catalog does not prove a vulnerability has never been exploited.

Technology tags indicate possible relevance, not verified exposure. Confirm the affected product, version, and configuration against your own inventory; KEVWire does not scan your systems.

A personal reading checklist on this device, not verified remediation.

Record JSON

Your account

Email alerts

Email alerts are coming as part of KEVWire Premium: join the waitlist. To follow your stack today, use its RSS feed, which honors your filters, or connect an AI agent through the API.

Suggest an improvement

Ideas, missing sources, corrections, and bugs are all welcome. No account needed. Suggestions are reviewed by a person before anything changes.

Record details

Record detail