Post

CVE-2026-49980: rclone rc --rc-serve inline remote backend instantiation

CVE-2026-49980: rclone rc --rc-serve inline remote backend instantiation

I reported a missing-authentication issue in rclone’s remote control file-serving handler that was published as CVE-2026-49980 / GHSA-qw24-gh76-8rvv.

The bug was in the GET/HEAD path exposed by rclone rcd --rc-serve. When the RC listener was reachable, global RC HTTP authentication was not configured, and --rc-serve was enabled, an unauthenticated request could supply a bracketed remote in the URL:

1
/[remote:path]/object

rclone parsed the remote component and instantiated it as a normal backend. Since rclone supports inline remote definitions, this let an unauthenticated request reach backend initialization with attacker-controlled options.

Advisory

  • CVE: CVE-2026-49980
  • GitHub Advisory: GHSA-qw24-gh76-8rvv
  • Package: github.com/rclone/rclone
  • Affected versions: >= 1.46.0, <= 1.74.2
  • Patched version: 1.74.3
  • Severity: Critical 9.8/10
  • CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
  • CWE: CWE-306: Missing Authentication for Critical Function

The impact changed across versions:

  • 1.46.0 to 1.54.x: unauthenticated local file read through the --rc-serve path.
  • 1.55.0 to 1.74.2: unauthenticated command execution became possible because inline backend option overrides were available.

Preconditions

The vulnerable deployment shape required all of the following:

  • the rclone remote control API was enabled, either with --rc or by running rclone rcd;
  • the RC HTTP listener was reachable by the attacker;
  • global RC HTTP authentication was not configured, for example no --rc-user, --rc-pass, or --rc-htpasswd;
  • --rc-serve was enabled.

This did not affect a plain rclone rcd instance unless --rc-serve was enabled.

Root Cause

The vulnerable logic lived in the RC file-serving path rather than the normal POST RC method dispatch path.

Before this issue, CVE-2026-41179 had already fixed unauthenticated backend instantiation through:

1
POST /operations/fsinfo

That fix protected the RC call dispatch path. However, --rc-serve exposed a separate GET/HEAD file-serving path. That path accepted bracketed remotes from the URL and instantiated them through the same backend creation machinery.

The important trust-boundary mistake was:

  1. unauthenticated HTTP request controls a bracketed remote string;
  2. the --rc-serve handler treats that string as a remote to serve;
  3. backend initialization processes inline backend options;
  4. some backend options have side effects during initialization.

For example, WebDAV supports bearer_token_command, and SFTP supports an external ssh command option. Both can execute local commands as part of backend startup.

Impact

The main impact was unauthenticated command execution as the rclone process user.

The public advisory describes the issue as network exploitable with no privileges and no user interaction when the RC listener is reachable and configured without HTTP authentication. The advisory was scored Critical with CVSS 9.8.

Additional primitives were also relevant:

  • GET and HEAD both triggered backend initialization.
  • Inline local remotes allowed unauthenticated local file read through the file-serving path.
  • global.* connection string options could mutate process-wide rclone configuration, including global.http_proxy.
  • Browser subresource requests could trigger the vulnerable path against a localhost-only RC listener. That was not the primary deployment precondition, but it made localhost-only deployments more interesting than they first appeared.

Why This Was Easy To Miss

The code path looked like file serving, not an administrative RC method.

The earlier fix for CVE-2026-41179 correctly focused on POST /operations/fsinfo, where attacker-controlled backend creation was visible as an RC method call. In contrast, the vulnerable path here was a GET/HEAD handler whose purpose was to serve configured remotes over HTTP.

The subtle part was that the URL syntax accepted by --rc-serve was powerful enough to describe more than a configured remote name. It could also describe inline remotes and connection string options. Once the serve path accepted that syntax from an unauthenticated request, it crossed the same backend-instantiation boundary that had already been recognized as dangerous in the POST path.

Fix Direction

rclone fixed the issue in 1.74.3 with two related commits.

The first fix added a checkServeRemote guard to the --rc-serve path. Unless the request is authenticated or --rc-no-auth is explicitly set, the serve path now only allows remotes already present in the config file. It rejects:

  • inline remote definitions;
  • connection string parameters;
  • bare local paths.

That prevents unauthenticated request-derived backend instantiation.

The second fix addressed the global.* side effect. RC-originated backend creation is now marked as an RC request, and global.* connection string options no longer mutate rclone’s process-wide configuration from RC paths. They may still apply to the individual backend context, but they do not leak into the rest of the process.

Lessons

The main lesson is that authentication checks need to follow the dangerous operation, not only the route that originally exposed it.

In this case, the dangerous operation was backend instantiation from attacker-controlled remote syntax. Once that operation could be reached from both POST RC methods and GET/HEAD file-serving paths, both paths needed equivalent authorization and input-shape restrictions.

For features like inline remotes and connection string overrides, it is also useful to separate “configured by an operator” from “supplied by an HTTP request”. They may share the same parser, but they do not have the same trust level.

References

This post is licensed under CC BY 4.0 by the author.