NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules
Last release 3 months ago
18 Jun 2026
Ships unpredictably
gaps range from 8 days to 6 months
Nearly every release is documented
notes for 22 of 22 stable releases
Nothing withdrawn
no release was ever pulled
9 years old
141 releases · first in 2017
Nothing published for this version
Update to cyphar.com/go-pathrs@0.2.5 , which included a build-time API breakage that we needed to work around. The API of this library is unchanged by
cyphar.com/go-pathrs@0.2.5, which included a build-time APIv0.7.0 offilepath-securejoin if they use the libpathrs built tag and have updatelibpathrs v0.2.5.Signed-off-by: Aleksa Sarai cyphar@cyphar.com
You talk of times of peace for all, and then prepare for war.
cyphar.com/go-pathrs@0.2.5, which included a build-time API
breakage that we needed to work around. The API of this library is unchanged
by this, but users should make sure to update to v0.7.0 of
filepath-securejoin if they use the libpathrs built tag and have update
to libpathrs v0.2.5.One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
This release includes a few more minor improvements to pathrs-lite, mainly involving the fallback logic in tools which configure seccomp profiles duri
This release includes a few more minor improvements to pathrs-lite,
mainly involving the fallback logic in tools which configure seccomp
profiles during execution (like runc) and to fix a file descriptor leak.
openat2(2) or fallback to an O_PATHopenat2(2). However, this causes issues when pathrs-lite is being used byopenat2(2) then we would return that error rather than falling backO_PATH resolver. To resolve this issue, we no longer cache theopenat2(2) was successful, only if there was an error.openat2 wrapper (when doing the necessarydup for RESOLVE_IN_ROOT) has been removed.Thanks to the following contributors for making this release possible:
Signed-off-by: Aleksa Sarai cyphar@cyphar.com
At last up jumped the cunning spider, and fiercely held her fast.
openat2(2) or fallback to an O_PATH
resolver would cache the result to avoid doing needless test runs of
openat2(2). However, this causes issues when pathrs-lite is being used by
a program that applies new seccomp-bpf filters onto itself -- if the filter
denies openat2(2) then we would return that error rather than falling back
to the O_PATH resolver. To resolve this issue, we no longer cache the
result if openat2(2) was successful, only if there was an error.openat2 wrapper (when doing the necessary
dup for RESOLVE_IN_ROOT) has been removed.The deprecated MkdirAll , MkdirAllHandle , OpenInRoot , OpenatInRoot and Reopen wrappers have been removed. Please switch to using pathrs-lite directl…
While quite small code-wise, this release marks a very key point in the
development of filepath-securejoin.
filepath-securejoin was originally intended (back in 2017) to simply be a
single-purpose library that would take some common code used in container
runtimes (specifically, Docker's FollowSymlinksInScope) and make it more
general-purpose (with the eventual goals of it ending up in the Go stdlib).
Of course, I quickly discovered that this problem was actually far more
complicated to solve when dealing with racing attackers, which lead to me
developing openat2(2) and libpathrs. I had originally planned for
libpathrs to completely replace filepath-securejoin "once it was ready" but in
the interim we needed to fix several race attacks in runc as part of security
advisories. Obviously we couldn't require the usage of a pre-0.1 Rust library
in runc so it was necessary to port bits of libpathrs into filepath-securejoin.
(Ironically the first prototypes of libpathrs were originally written in Go and
then rewritten to Rust, so the code in filepath-securejoin is actually Go code
that was rewritten to Rust then re-rewritten to Go.)
It then became clear that pure-Go libraries will likely not be willing to
require CGo for all of their builds, so it was necessary to accept that
filepath-securejoin will need to stay. As such, in v0.5.0 we provided more
pure-Go implementations of features from libpathrs but moved them into
pathrs-lite subpackage to clarify what purpose these helpers serve.
This release finally closes the loop and makes it so that pathrs-lite can
transparently use libpathrs (via a libpathrs build-tag). This means that
upstream libraries can use the pure Go version if they prefer, but downstreams
(either downstream library users or even downstream distributions) are able to
migrate to libpathrs for all usages of pathrs-lite in an entire Go binary.
I should make it clear that I do not plan to port the rest of libpathrs to Go,
as I do not wish to maintain two copies of the same codebase. pathrs-lite
already provides the core essentials necessary to operate on paths safely for
most modern systems. Users who want additional hardening or more ergonomic APIs
are free to use cyphar.com/go-pathrs (libpathrs's Go bindings).
MkdirAll, MkdirAllHandle, OpenInRoot, OpenatInRoot andReopen wrappers have been removed. Please switch to using pathrs-litepathrs-lite now has support for using libpathrs as a backend.libpathrs buildgithub.com/cyphar/filepath-securejoin/pathrs-litelibpathrs for the entireSigned-off-by: Aleksa Sarai cyphar@cyphar.com
Nothing published for this version
This release includes a few more minor improvements to pathrs-lite, mainly involving the fallback logic in tools which configure seccomp profiles duri
This release includes a few more minor improvements to pathrs-lite,
mainly involving the fallback logic in tools which configure seccomp
profiles during execution (like runc) and to fix a file descriptor leak.
openat2(2) or fallback to an O_PATHopenat2(2). However, this causes issues when pathrs-lite is being used byopenat2(2) then we would return that error rather than falling backO_PATH resolver. To resolve this issue, we no longer cache theopenat2(2) was successful, only if there was an error.openat2 wrapper (when doing the necessarydup for RESOLVE_IN_ROOT) has been removed.Thanks to the following contributors for making this release possible:
Signed-off-by: Aleksa Sarai cyphar@cyphar.com
"Will you walk into my parlour?" said a spider to a fly.
openat2(2) or fallback to an O_PATH
resolver would cache the result to avoid doing needless test runs of
openat2(2). However, this causes issues when pathrs-lite is being used by
a program that applies new seccomp-bpf filters onto itself -- if the filter
denies openat2(2) then we would return that error rather than falling back
to the O_PATH resolver. To resolve this issue, we no longer cache the
result if openat2(2) was successful, only if there was an error.openat2 wrapper (when doing the necessary
dup for RESOLVE_IN_ROOT) has been removed.Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
openat2 can return -EAGAIN if it detects a possible attack in certain scenarios (namely if there was a rename or mount while walking a path with a ..
openat2 can return -EAGAIN if it detects a possible attack in certain
scenarios (namely if there was a rename or mount while walking a path with a
.. component). While this is necessary to avoid a denial-of-service in the
kernel, it does require retry loops in userspace.
In previous versions, pathrs-lite would retry openat2 32 times before
returning an error, but we've received user reports that this limit can be
hit on systems with very heavy load. In some synthetic benchmarks (testing
the worst-case of an attacker doing renames in a tight loop on every core of
a 16-core machine) we managed to get a ~3% failure rate in runc. We have
improved this situation in two ways:
We have now increased this limit to 128, which should be good enough for
most use-cases without becoming a denial-of-service vector (the number of
syscalls called by the O_PATH resolver in a typical case is within the
same ballpark). The same benchmarks show a failure rate of ~0.12% which
(while not zero) is probably sufficient for most users.
In addition, we now return a unix.EAGAIN error that is bubbled up and can
be detected by callers. This means that callers with stricter requirements
to avoid spurious errors can choose to do their own infinite EAGAIN retry
loop (though we would strongly recommend users use time-based deadlines in
such retry loops to avoid potentially unbounded denials-of-service).
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
…work around those). In addition, STATX_MNT_ID is vulnerable to mount ID reuse attacks by sufficiently motivated and privileged attackers -- this probl…
NOTE: With this release, some parts of
github.com/cyphar/filepath-securejoin
are now licensed under the Mozilla Public License (version 2). Please see
COPYING.md as well as the the license header in each file for more details.
The new API introduced in the 0.3.0 release has been moved to a new
subpackage called pathrs-lite. This was primarily done to better indicate
the split between the new and old APIs, as well as indicate to users the
purpose of this subpackage (it is a less complete version of libpathrs).
We have added some wrappers to the top-level package to ease the transition,
but those are deprecated and will be removed in the next minor release of
filepath-securejoin. Users should update their import paths.
This new subpackage has also been relicensed under the Mozilla Public License
(version 2), please see COPYING.md for more details.
Most of the key bits the safe procfs API have now been exported and are
available in github.com/cyphar/filepath-securejoin/pathrs-lite/procfs. At
the moment this primarily consists of a new procfs.Handle API:
OpenProcRoot returns a new handle to /proc, endeavouring to make it
safe if possible (subset=pid to protect against mistaken write attacks
and leaks, as well as using fsopen(2) to avoid racing mount attacks).
OpenUnsafeProcRoot returns a handle without attempting to create one
with subset=pid, which makes it more dangerous to leak. Most users
should use OpenProcRoot (even if you need to use ProcRoot as the base
of an operation, as filepath-securejoin will internally open a handle when
necessary).
The (*procfs.Handle).Open* family of methods lets you get a safe
O_PATH handle to subpaths within /proc for certain subpaths.
For OpenThreadSelf, the returned ProcThreadSelfCloser needs to be
called after you completely finish using the handle (this is necessary
because Go is multi-threaded and ProcThreadSelf references
/proc/thread-self which may disappear if we do not
runtime.LockOSThread -- ProcThreadSelfCloser is currently equivalent
to runtime.UnlockOSThread).
Note that you cannot open any procfs symlinks (most notably magic-links)
using this API. At the moment, filepath-securejoin does not support this
feature (but libpathrs does).
ProcSelfFdReadlink lets you get the in-kernel path representation of a
file descriptor (think readlink("/proc/self/fd/...")), except that we
verify that there aren't any tricky overmounts that could fool the
process.
Please be aware that the returned string is simply a snapshot at that
particular moment, and an attacker could move the file being pointed to.
In addition, complex namespace configurations could result in non-sensical
or confusing paths to be returned. The value received from this function
should only be used as secondary verification of some security property,
not as proof that a particular handle has a particular path.
The procfs handle used internally by the API is the same as the rest of
filepath-securejoin (for privileged programs this is usually a private
in-process procfs instance created with fsopen(2)).
As before, this is intended as a stop-gap before users migrate to
libpathrs, which provides a far more extensive safe procfs API and is
generally more robust.
Previously, the hardened procfs implementation (used internally within
Reopen and Open(at)InRoot) only protected against overmount attacks on
systems with openat2(2) (Linux 5.6) or systems with fsopen(2) or
open_tree(2) (Linux 5.2) and programs with privileges to use them (with
some caveats about locked mounts that probably affect very few users). For
other users, an attacker with the ability to create malicious mounts (on most
systems, a sysadmin) could trick you into operating on files you didn't
expect. This attack only really makes sense in the context of container
runtime implementations.
This was considered a reasonable trade-off, as the long-term intention was to
get all users to just switch to libpathrs if they wanted to use the safe
procfs API (which had more extensive protections, and is what these new
protections in filepath-securejoin are based on). However, as the API
is now being exported it seems unwise to advertise the API as "safe" if we do
not protect against known attacks.
The procfs API is now more protected against attackers on systems lacking the
aforementioned protections. However, the most comprehensive of these
protections effectively rely on statx(STATX_MNT_ID) (Linux 5.8).
On older kernel versions, there is no effective protection (there is some
minimal protection against non-procfs filesystem components but a
sufficiently clever attacker can work around those). In addition,
STATX_MNT_ID is vulnerable to mount ID reuse attacks by sufficiently
motivated and privileged attackers -- this problem is mitigated with
STATX_MNT_ID_UNIQUE (Linux 6.8) but that raises the minimum kernel version
for more protection.
The fact that these protections are quite limited despite needing a fair bit
of extra code to handle was one of the primary reasons we did not initially
implement this in filepath-securejoin (libpathrs supports all of this,
of course).
fsopen(2) but in some testing we've foundfsopen(2) if the running kernel version isopen("/proc").Thanks to the following contributors who made this release possible:
Signed-off-by: Aleksa Sarai cyphar@cyphar.com
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →