This release includes 7 security fixes for security teams reviewing exposed deployments.
Topics
+14 more
Affected surfaces
Summary
AI summarySecurity hardening release closes seven local privilege‑escalation vectors when using --use-sudo.
Full changelog
v3.1.1 — 2026-05-18
Security hardening release. Closes seven local privilege-escalation
vectors that an unprivileged attacker on the same host could chain
through --use-sudo. No new features, no behavior change for
non-elevated copies of regular files. Threat model: a non-root attacker
with write access to either the source tree, the destination tree,
the script, or the script's directory tries to redirect root-privileged
I/O (planted symlinks, hardlinks, group-writable script, sudo-mode
auto-update) to a target only root can touch.
Security fixes
-
Symlink-safe destination writes. The copy / sparse-copy / SFTP /
tar-extract paths now open destination files withO_NOFOLLOWand
applychmodvia the open fd (fchmod). A non-root attacker can no
longer pre-plant<dst>/file -> /root/.bashrcand trick a sudo run
into overwriting an arbitrary root-owned file. -
Symlink-safe source enumeration.
os.walknow uses
followlinks=Falseon POSIX (Windows junctions unaffected). The
scannerlstats each candidate: under sudo oreuid==0all
symlinks are refused with a visible "Skipped N symlinks" message;
for non-elevated runs only symlinks whose realpath escapes the
source tree are skipped, so in-tree symlinks keep working. -
TOCTOU-safe source reads under sudo. All file-read producers
(copy_individual,_copy_sparse,copy_block_streamsmall-file
tar pipe,copy_to_remote_sftp,copy_tar_stream_remote) route
through a shared_safe_open_read_fd()that addsO_NOFOLLOWwhen
elevated, so an attacker who races the scan→copy window cannot swap
a regular file for a symlink and exfiltrate/etc/shadowor the
like. Non-elevated runs still resolve in-tree symlinks normally. -
Audit file moved to invoking user's home. The hidden
.fast_copy_audit.jsonlnow lives in~$SUDO_USERinstead of the
copy destination, so an attacker who controls the destination path
can no longer pre-plant the audit filename as a symlink to
/etc/shadowand trick root intochattr +i/chmod 0600/
appending on a sensitive file. The audit open uses
O_NOFOLLOW | O_APPEND | O_CREAT,fchmodvia fd, and an
st_nlink > 1refusal so hardlink-pinned targets are also blocked. -
--updaterefused under sudo. Self-update aborts when
geteuid() == 0or$SUDO_USERis set. A compromised release
publisher can therefore only install code that runs as the invoking
user — the user must explicitly re-elevate via a separatesudo
invocation before the new binary touches root. -
Optional
--update-sha256 <hex>pin. When supplied, the
downloaded binary's SHA-256 is compared to a 64-char hex value (e.g.
copied from the GitHub release page) and the update is refused on
mismatch. The hash is validated for format up front. Without the
flag, existing HTTPS / hostname-allowlist / size checks still apply
but no integrity pinning is performed. -
--use-sudopreflight on script & interpreter. Before
re-executing under sudo, fast-copy refuses iffast_copy.py, its
parent directory, orsys.executableis owned by anyone other than
root or the invoking user, or is group/world-writable. Closes the
trojan-the-script path: an attacker in your group can no longer
silently editfast_copy.pyand wait for your next sudo run.
Other changes
-
SSH
known_hostsrouted to invoking user under sudo. Accepted
host keys are written to~$SUDO_USER/.ssh/known_hostsand chowned
back to that user, so TOFU acceptance persists for the human
operator rather than disappearing into/root/.ssh/. -
check_exploits.py— new verification script that reproduces
each of the eleven attack scenarios (planted symlinks at source /
destination / audit path, simulated elevated runs, group-writable
script, world-writable script directory, refused--updateunder
sudo,--update-sha256format check, known_hosts routing, TOCTOU
race) without requiring real root, and asserts each vector is
refused. Run withpython3 check_exploits.py.
Compatibility
No CLI changes for existing workflows. Non-elevated copies of regular
files and in-tree symlinks behave identically to v3.1.0. Sudo runs
will now log a "Skipped N symlinks" line if the source contains any
symlinks (intentional — they were previously followed silently). The
sudo audit file now lives in ~$SUDO_USER/.fast_copy_audit.jsonl
instead of <dst>/.fast_copy_audit.jsonl; old audit files in
destinations are left in place and ignored.
Security Fixes
- Symlink‑safe destination writes using O_NOFOLLOW for root‑privileged copies
- Symlink‑safe source enumeration with followlinks=False and explicit skip of out‑of‑tree symlinks
- TOCTOU‑safe source reads under sudo via O_NOFOLLOW on elevated file opens
- Audit file moved to invoking user's home directory with O_NOFOLLOW, O_APPEND, and hardlink refusal
- --update flag now refused when run under sudo (geteuid()==0 or $SUDO_USER set)
- Optional --update-sha256 pin adds SHA‑256 integrity check for self‑updates
- `--use-sudo` preflight refuses execution if script, its directory, or interpreter is not owned by root or the invoking user and is group/world‑writable
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Fast_copy new release with new features
All releases →Related context
Related tools
Beta — feedback welcome: [email protected]