GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

GHSA-XWWR-4H3P-R22C

Vulnerability from github – Published: 2026-09-10 22:49 – Updated: 2026-09-10 22:49
VLAI
Summary
rclone serve s3: --auth-proxy without --auth-key authenticates nobody - full SigV4 signature bypass
Details

Summary

rclone serve s3's handler chain, when --auth-proxy is configured, is (outermost first): authPairMiddleware -> proxyAuthMiddleware -> gofakes3's own SigV4-verifying handler.

authPairMiddleware parses the accessKeyID straight out of the incoming request's own Authorization header (entirely client-controlled) and registers {accessKey: ws.s3Secret} into gofakes3's shared credential store via AddAuthKeys, for EVERY access key any client presents - not just ones previously known to the server. ws.s3Secret defaults to "" whenever --auth-key is not set, which the --auth-proxy documentation (and the reference bin/test_proxy.py) presents as a complete, standalone authentication mechanism requiring no other flag - matching how it's used for serve webdav/ftp/sftp.

gofakes3's SigV4 verification then checks the request's signature against exactly the secret authPairMiddleware just registered for that same client-chosen key. An empty string is a valid HMAC key, so a caller can trivially compute a correct SigV4 signature for ANY access key ID of their choosing using an empty secret, and verification passes.

Crucially, the auth-proxy script never receives a real secret to verify against, for S3 specifically: Server.auth() calls w.proxy.Call(md5(accessKeyID), accessKeyID, false, r.RemoteAddr) - passing the access key ID itself as BOTH the hashed "user" and the raw "auth"/password fields. Contrast with serve webdav/ftp/sftp, whose proxy integration passes the client's actual typed password (see bin/test_proxy.py, which forwards it into a backing SFTP login for real verification). For S3, no independent secret is ever transmitted to the proxy script at all, so no script - however carefully written - can distinguish a legitimate holder of an access key ID from an attacker who merely picked the same string.

Net effect: with --auth-proxy configured and --auth-key not also set (the configuration the feature is documented to support standalone), SigV4 signature verification authenticates nobody.

Details

Vulnerable code (before fix):

func authPairMiddleware(next http.Handler, ws *Server) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        accessKey, _ := parseAccessKeyID(r)
        authPair := map[string]string{accessKey: ws.s3Secret}
        ws.faker.AddAuthKeys(authPair)
        next.ServeHTTP(w, r)
    })
}

PoC

Built and signed a request by hand (via the vendored github.com/aws/aws-sdk-go-v2/aws/signer/v4) using a freshly-random access key ID never configured or returned by anything, with SecretAccessKey: "", against a real rclone serve s3 --auth-proxy <script> instance with no --auth-key set:

status=200
<ListAllMyBucketsResult>...<Bucket><Name>mybucket</Name>...

A fully authenticated, successful bucket listing, with zero prior credential knowledge.

Impact

Any network-reachable, unauthenticated attacker who knows (or discovers) that a target is running rclone serve s3 --auth-proxy without --auth-key can choose an arbitrary access key ID, sign a request against an empty secret, and be treated as an authenticated user by the auth-proxy script - reaching whatever backend that script resolves the chosen identity to. No credentials, prior access, or user interaction of any kind are required.

Fix

Refuse to start rclone serve s3 when --auth-proxy is set without --auth-key, rather than silently falling back to a signature check that authenticates nobody:

if proxyOpt.AuthProxy != "" && len(opt.AuthKey) == 0 {
    return nil, errors.New("serve s3: --auth-proxy requires --auth-key to also be set (SigV4 has no other way to verify a signature for a dynamically-proxied identity)")
}

Note this is a minimal fix for the zero-knowledge bypass; once --auth-key is also set, every access key ID still shares that one static secret for signature-verification purposes (a caller who knows it can request any identity from the proxy script) - a narrower, pre-existing limitation flagged for awareness but not changed here, since a complete fix needs the auth-proxy wire protocol to carry a per-identity secret for S3 specifically (a larger design change).

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/rclone/rclone"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.75.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-88018"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-306"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T22:49:07Z",
    "nvd_published_at": "2026-09-10T16:18:08Z",
    "severity": "CRITICAL"
  },
  "details": "### Summary\n`rclone serve s3`\u0027s handler chain, when `--auth-proxy` is configured, is (outermost first): `authPairMiddleware` -\u003e `proxyAuthMiddleware` -\u003e gofakes3\u0027s own SigV4-verifying handler.\n\n`authPairMiddleware` parses the accessKeyID straight out of the incoming request\u0027s own `Authorization` header (entirely client-controlled) and registers `{accessKey: ws.s3Secret}` into gofakes3\u0027s shared credential store via `AddAuthKeys`, for EVERY access key any client presents - not just ones previously known to the server. `ws.s3Secret` defaults to `\"\"` whenever `--auth-key` is not set, which the `--auth-proxy` documentation (and the reference `bin/test_proxy.py`) presents as a complete, standalone authentication mechanism requiring no other flag - matching how it\u0027s used for `serve webdav`/`ftp`/`sftp`.\n\ngofakes3\u0027s SigV4 verification then checks the request\u0027s signature against exactly the secret `authPairMiddleware` just registered for that same client-chosen key. An empty string is a valid HMAC key, so a caller can trivially compute a correct SigV4 signature for ANY access key ID of their choosing using an empty secret, and verification passes.\n\nCrucially, the auth-proxy script never receives a real secret to verify against, for S3 specifically: `Server.auth()` calls `w.proxy.Call(md5(accessKeyID), accessKeyID, false, r.RemoteAddr)` - passing the access key ID itself as BOTH the hashed \"user\" and the raw \"auth\"/password fields. Contrast with `serve webdav`/`ftp`/`sftp`, whose proxy integration passes the client\u0027s actual typed password (see `bin/test_proxy.py`, which forwards it into a backing SFTP login for real verification). For S3, no independent secret is ever transmitted to the proxy script at all, so no script - however carefully written - can distinguish a legitimate holder of an access key ID from an attacker who merely picked the same string.\n\nNet effect: with `--auth-proxy` configured and `--auth-key` not also set (the configuration the feature is documented to support standalone), SigV4 signature verification authenticates nobody.\n\n### Details\nVulnerable code (before fix):\n```go\nfunc authPairMiddleware(next http.Handler, ws *Server) http.Handler {\n\treturn http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\taccessKey, _ := parseAccessKeyID(r)\n\t\tauthPair := map[string]string{accessKey: ws.s3Secret}\n\t\tws.faker.AddAuthKeys(authPair)\n\t\tnext.ServeHTTP(w, r)\n\t})\n}\n```\n\n### PoC\nBuilt and signed a request by hand (via the vendored `github.com/aws/aws-sdk-go-v2/aws/signer/v4`) using a freshly-random access key ID never configured or returned by anything, with `SecretAccessKey: \"\"`, against a real `rclone serve s3 --auth-proxy \u003cscript\u003e` instance with no `--auth-key` set:\n```\nstatus=200\n\u003cListAllMyBucketsResult\u003e...\u003cBucket\u003e\u003cName\u003emybucket\u003c/Name\u003e...\n```\nA fully authenticated, successful bucket listing, with zero prior credential knowledge.\n\n### Impact\nAny network-reachable, unauthenticated attacker who knows (or discovers) that a target is running `rclone serve s3 --auth-proxy` without `--auth-key` can choose an arbitrary access key ID, sign a request against an empty secret, and be treated as an authenticated user by the auth-proxy script - reaching whatever backend that script resolves the chosen identity to. No credentials, prior access, or user interaction of any kind are required.\n\n### Fix\nRefuse to start `rclone serve s3` when `--auth-proxy` is set without `--auth-key`, rather than silently falling back to a signature check that authenticates nobody:\n```go\nif proxyOpt.AuthProxy != \"\" \u0026\u0026 len(opt.AuthKey) == 0 {\n\treturn nil, errors.New(\"serve s3: --auth-proxy requires --auth-key to also be set (SigV4 has no other way to verify a signature for a dynamically-proxied identity)\")\n}\n```\nNote this is a minimal fix for the zero-knowledge bypass; once `--auth-key` is also set, every access key ID still shares that one static secret for signature-verification purposes (a caller who knows it can request any identity from the proxy script) - a narrower, pre-existing limitation flagged for awareness but not changed here, since a complete fix needs the auth-proxy wire protocol to carry a per-identity secret for S3 specifically (a larger design change).",
  "id": "GHSA-xwwr-4h3p-r22c",
  "modified": "2026-09-10T22:49:07Z",
  "published": "2026-09-10T22:49:07Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rclone/rclone/security/advisories/GHSA-xwwr-4h3p-r22c"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-88018"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rclone/rclone/commit/90595f34f27f569be6b27c57fe5ab65057d323bd"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rclone/rclone"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rclone/rclone/releases/tag/v1.75.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "rclone serve s3: --auth-proxy without --auth-key authenticates nobody - full SigV4 signature bypass"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Loading…