Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹 Go

GHSA-945v-v9p3-v5xw

LOW

GHSA-945v-v9p3-v5xw is a low-severity (CVSS 3.6) vulnerability in github.com/rclone/rclone. O3 Security confirms whether GHSA-945v-v9p3-v5xw is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

rclone local `--metadata` applies attacker-controlled mode/uid - setuid binary planted from an untrusted remote

Published
Aug 5, 2026
Updated
Aug 5, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

Blast Radius

1 pkg affected
🐹github.com/rclone/rclone

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Summary

When writing an object with metadata, the local backend applies the source-supplied mode, uid, and gid verbatim: it parses mode as an octal integer and passes it straight into os.Chmod(o.path, os.FileMode(umode)), and passes uid/gid straight into os.Chown. The value is never masked to permission bits, so any value with Go's ModeSetuid (1<<23) or ModeSetgid (1<<22) bit set causes the setuid/setgid bit to be applied. Because both the file content and its metadata come from the (attacker-controlled) source remote, an attacker stores a binary of their choosing with mode = 40000755 (and uid = 0); when the victim runs rclone copy -M <remote>: /dest, rclone writes the attacker's binary and makes it setuid. If the victim runs rclone as root (typical for system backup/restore), the uid=0 chown plus setuid produces a root-owned setuid binary with attacker content — any local user then escalates to root. When rclone runs as a non-root service user, the planted setuid binary is owned by that user, giving any local user that user's privileges (lateral escalation / persistent backdoor).

Details

backend/local/metadata.go, writeMetadataToFile():

uid, hasUID := o.parseMetadataInt(m, "uid", 10)
gid, hasGID := o.parseMetadataInt(m, "gid", 10)
if hasUID {
    ...
    err = os.Chown(o.path, uid, gid)        // source-controlled owner, no same-uid guard
}
mode, hasMode := o.parseMetadataInt(m, "mode", 8)
if hasMode && mode >= 0 {
    umode := uint(mode)
    if umode <= math.MaxUint32 {
        err = os.Chmod(o.path, os.FileMode(umode))   // <-- raw value; ModeSetuid/ModeSetgid NOT masked off
    }
}

os.Chmod/os.FileMode honor ModeSetuid/ModeSetgid/ModeSticky. There is no &^ (os.ModeSetuid|os.ModeSetgid) mask and no check that the source is trusted, so an attacker-chosen mode string sets those bits on the freshly written, attacker-controlled file. (Note: a legitimate local source reports mode in unix st_mode layout e.g. 0106755, whose bit 1<<23 is unset, so honest copies happen to drop setuid — but the attacker supplies the Go-FileMode layout 40000755 directly, which sets it.)

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
  1. Create a payload (the attacker-controlled binary content) and copy it with the malicious mode metadata:
mkdir -p msrc mdst && cp /bin/true msrc/payload
./rclone copy -M --metadata-set mode=40000755 msrc mdst       # 40000755 = Go FileMode setuid|0755
  1. Observe — the destination file is now setuid:
stat -c '%A %a' mdst/payload
-rwsr-xr-x 4755                                               # 's' = setuid bit SET on attacker binary

Variants: mode=20000755 → setgid (-rwxr-sr-x); mode=60000755 → both (-rwsr-sr-x). With rclone run as root and the source object also carrying uid=0/gid=0, the file is chown'd root:root, yielding a root-owned setuid binary executable by any local user.

Impact

A victim performing a metadata-preserving copy/restore (-M) from an untrusted or compromised remote installs an attacker-chosen executable with the setuid/setgid bit set. Run as root (system backup/restore, the common case for --metadata), this is a root-owned setuid root backdoor executable by any local user → local privilege escalation to root. Run as a non-root user, it is a setuid backdoor for that service account. The companion uid/gid application lets a root-run transfer also reassign ownership of written files arbitrarily.

Remediation

Mask special bits before applying mode from metadata — os.Chmod(o.path, os.FileMode(umode).Perm()) (or umode & 0o777) — and do not honor setuid/setgid/sticky from source metadata; gate uid/gid/setuid application behind an explicit opt-in (e.g. --local-metadata-set-ownership) that is off by default, and document that -M from untrusted remotes must not restore privileged bits. Regression test: copying an object with mode=40000755/uid=0 must produce a non-setuid, caller-owned file unless the opt-in is set.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/rclone/rcloneall versions1.74.4

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/rclone/rclone. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update github.com/rclone/rclone to 1.74.4 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-945v-v9p3-v5xw is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-945v-v9p3-v5xw is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-945v-v9p3-v5xw. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### Summary When writing an object with metadata, the local backend applies the source-supplied `mode`, `uid`, and `gid` verbatim: it parses `mode` as an octal integer and passes it straight into `os.Chmod(o.path, os.FileMode(umode))`, and passes `uid`/`gid` straight into `os.Chown`. The value is never masked to permission bits, so any value with Go's `ModeSetuid` (1<<23) or `ModeSetgid` (1<<22) bit set causes the setuid/setgid bit to be applied. Because both the file content and its metadata come from the (attacker-controlled) source remote, an attacker stores a binary of their choosing with
O3 Security · Impact-Aware SCA

Is GHSA-945v-v9p3-v5xw in your dependencies?

O3 detects GHSA-945v-v9p3-v5xw across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.