rclone is a command-line program to sync files and directories to and from different cloud storage providers. Prior to 1.75.1, rclone core does not reject parent-directory segments in source Object.Remote() values before fs/list, fs/walk, fs/sync, and fs/operations pass those values to destination backends. A flat-keyspace source object store populated with native non-rclone tooling can contain a raw .. key segment, and affected b2, swift, qingstor, oracleobjectstorage, internetarchive, smb, storj, sftp, webdav, ftp, filelu, shade, and sia destinations use path.Join(root, remote) before EncodeDot can neutralize the segment. A copy or upload can therefore escape the configured root into another bucket, share, or path reachable by the victim credential, with sftp and smb potentially reaching other filesystem or share locations under the same login authority. This issue is fixed in version 1.75.1.
rclone is a command-line program to sync files and directories to and from different cloud storage providers. Prior to 1.75.1, rclone core does not reject parent-directory segments in source Object.Remote() values before fs/list, fs/walk, fs/sync, and fs/operations pass those values to destination backends. A flat-keyspace source object store populated with native non-rclone tooling can contain a raw .. key segment, and affected b2, swift, qingstor, oracleobjectstorage, internetarchive, smb, storj, sftp, webdav, ftp, filelu, shade, and sia destinations use path.Join(root, remote) before EncodeDot can neutralize the segment. A copy or upload can therefore escape the configured root into another bucket, share, or path reachable by the victim credential, with sftp and smb potentially reaching other filesystem or share locations under the same login authority. This issue is fixed in version 1.75.1.
rclone is a command-line program to sync files and directories to and from different cloud storage providers. Prior to 1.75.1, rclone core does not reject parent-directory segments in source Object.Remote() values before fs/list, fs/walk, fs/sync, and fs/operations pass those values to destination backends. A flat-keyspace source object store populated with native non-rclone tooling can contain a raw .. key segment, and affected b2, swift, qingstor, oracleobjectstorage, internetarchive, smb, storj, sftp, webdav, ftp, filelu, shade, and sia destinations use path.Join(root, remote) before EncodeDot can neutralize the segment. A copy or upload can therefore escape the configured root into another bucket, share, or path reachable by the victim credential, with sftp and smb potentially reaching other filesystem or share locations under the same login authority. This issue is fixed in version 1.75.1.
### Summary
Multiple backends, when given a specially crafted object to copy, can escape the backend confinement.
| Backend | Keep/Close | Per-backend severity |
|---|---|---|
| sftp | Medium | Real filesystem escape, fires under default encoding. |
| smb | Low-Medium | Escapes to a different SMB share the credential can reach. |
| ftp | Low | Real, leading-`..` overshoot PoC is partly neutralized by encoding; escape bounded to at/below the login base. |
| webdav | Low | Server-side ACLs are the real boundary. |
| b2 | Low | Same-account sibling **bucket** crossing on a flat keyspace. |
| swift | Low | Same, container. |
| qingstor | Low | Same. |
| oracleobjectstorage | Low | Same. |
| internetarchive | Low | IA items are owner-writable only; confined to user's own items. |
| storj | Low | Can retarget a different bucket in the same access grant. |
| filelu | Low | Confined to the user's own account. |
| shade | Low | Confined to the user's own drive. |
| sia | Low | siad API password already grants full-daemon access. |
## Root cause
rclone core does **not** sanitize `..` in a source object's `Remote()` - verified: nothing in `fs/march`, `fs/sync`, `fs/list`, or `fs/operations` rejects `..` segments before the name reaches the destination backend's `Put`/`Update`/`Mkdir`. Confinement is therefore each backend's responsibility, and these backends join `root + remote` without a check.
This divides into two classes:
- **Bucket based backends** - `bucket.Split(path.Join(f.root, rootRelativePath))`:
- `backend/b2/b2.go:404`, `backend/swift/swift.go:464`, `backend/qingstor/qingstor.go:198`, `backend/oracleobjectstorage/oracleobjectstorage.go:245`, `backend/internetarchive/internetarchive.go:1016`, `backend/smb/smb.go:885`, `backend/storj/fs.go:289`.
- `path.Join` collapses `..` on the standard (ASCII) form **before** encoding is applied (e.g. `FromStandardPath(path.Join(...))` at `backend/b2/b2.go:1641`), so `EncodeDot` never gets the chance to neutralize the `..`.
- `lib/bucket.Join` does **not** clean paths (keeps `..` as a literal key segment); `path.Join` does. `backend/s3`, `backend/azureblob`, `backend/googlecloudstorage` already use `bucket.Join` and are therefore not affected.
- **Path based backends** - `path.Join(root, remote)` onto a real path:
- sftp: `remotePath = path.Join(f.absRoot, f.opt.Enc.FromStandardPath(remote))` (`backend/sftp/sftp.go:2497`). Default encoding is `encoder.Display` (== `Standard`), and `FromStandardPath` short-circuits to a pass-through in that mode, so `..` survives; `f.absRoot` is absolute, so `path.Join("/home/user/root", "../../../../etc/passwd")` -> `/etc/passwd`.
- webdav: `filePath` at `backend/webdav/webdav.go:426-432`.
- ftp: `path.Join(f.root, remote)` at ~14 sites (e.g. `backend/ftp/ftp.go:1247`).
- filelu, shade, sia: analogous joins.
### Precondition that limits reachability
For any of these to fire, a **source** must hand rclone a `Remote()` containing raw `..`. That is only possible when:
1. the source is a **flat-keyspace object store** (not a filesystem - a local/sftp/smb source cannot represent `../../x` as one directory entry), **and**
2. the offending key was written with **native, non-rclone tooling** - rclone's own writer applies `EncodeDot` and rewrites a `..` segment to fullwidth `..`, so you cannot create such a key *through rclone*.
rclone's source-side listing does pass a natively-planted raw `..` key through unchanged (verified for b2: `remote := file.Name[len(prefix):]` after `ToStandardPath`, `backend/b2/b2.go:858,867`). The reports never establish this precondition; it is the same omission across every member of the class.
### Example attack
```bash
# Step 1 - attacker, using NATIVE S3 tooling (NOT rclone) on a source the victim ingests from:
aws s3api put-object --bucket shared-drop --key '../../victim-backups/pwned.txt' --body evil.txt
# Step 2 - victim's ordinary ingest:
rclone copy s3-drop:shared-drop b2:victim-uploads/incoming
# path.Join("victim-uploads/incoming", "../../victim-backups/pwned.txt") = "victim-backups/pwned.txt"
# -> lands in the victim's victim-backups bucket instead of under incoming/
```
The blast radius is the victim's **own** account (a bucket/share/path the configured credential already reaches) - integrity misdirection, not a cross-tenant or confidentiality breach. sftp/smb are the exception in *reach* (server filesystem / other share), still bounded by the login's own permissions.
## Precedent
This is the same class as the already-fixed local backend advisory [https://github.com/rclone/rclone/security/advisories/GHSA-7p4m-qxvv-g567](GHSA-7p4m-qxvv-g567), which added `(*Fs).localPath` returning `errPathEscapes` for names resolving outside the root (`backend/local/local.go:819-826`). That fix was justified because the destination was the operator's own OS filesystem; the same reasoning extends (at lower severity) to sftp/smb.
EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.
Original publisher date fields
datePublished: Sep 10, 2026, 4:14:49 PM
dateUpdated: Sep 15, 2026, 2:47:32 PM
No normalized affected-package data is projected for this source revision. The original publisher record may contain additional product and version evidence; this does not establish that a package is unaffected.
NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.
Source analysis status: Awaiting Analysis
Weakness classifications: CWE-22
Original publisher date fields
published: 2026-09-10T17:17:08.677
lastModified: 2026-09-15T15:17:24.440
No normalized affected-package data is projected for this source revision. The original publisher record may contain additional product and version evidence; this does not establish that a package is unaffected.