Refuse credentials in a storage URL's endpoint or rclone remote name #352

Merged
clawbot merged 1 commits from issue-322-storage-url-nested-credentials into next 2026-10-14 03:26:03 +02:00
Collaborator

Fixes #322.

storage_url refused credentials only in the outer URL's user info and in unknown query parameters. User info inside the endpoint= value of an s3:// URL, and rclone's remote,param=value parameters in the remote name of an rclone:// URL, were accepted and then printed by info, remote info and snapshot create.

ParseStorageURL now refuses these, and the error never contains the value:

  • An endpoint= value containing @ is refused with the existing credentials error. A host name never contains @, so this catches the endpoint with or without a scheme. Every endpoint= value is checked, because info prints the raw storage_url.
  • An s3:// or rclone:// query that cannot be decoded (a ;, or a % not followed by two hex digits) is refused with a new error. Decoding drops such a part, so an endpoint= holding user info, or any rclone:// query parameter, would escape the checks. The decode error, which can quote the value, is not passed on.
  • An rclone remote name containing , is refused with a new error that points at rclone config. rclone remote names never contain a comma. The name is taken from the raw URL and checked before url.Parse, whose error for such a name prints it from the colon on.

Judgement call: the rclone remote name case gets its own error rather than the credentials error, which tells the reader to set s3.access_key_id and s3.secret_access_key.

Model: opus-5-5

Fixes https://git.eeqj.de/sneak/vaultik/issues/322. `storage_url` refused credentials only in the outer URL's user info and in unknown query parameters. User info inside the `endpoint=` value of an `s3://` URL, and rclone's `remote,param=value` parameters in the remote name of an `rclone://` URL, were accepted and then printed by `info`, `remote info` and `snapshot create`. `ParseStorageURL` now refuses these, and the error never contains the value: - An `endpoint=` value containing `@` is refused with the existing credentials error. A host name never contains `@`, so this catches the endpoint with or without a scheme. Every `endpoint=` value is checked, because `info` prints the raw `storage_url`. - An `s3://` or `rclone://` query that cannot be decoded (a `;`, or a `%` not followed by two hex digits) is refused with a new error. Decoding drops such a part, so an `endpoint=` holding user info, or any `rclone://` query parameter, would escape the checks. The decode error, which can quote the value, is not passed on. - An rclone remote name containing `,` is refused with a new error that points at `rclone config`. rclone remote names never contain a comma. The name is taken from the raw URL and checked before `url.Parse`, whose error for such a name prints it from the colon on. Judgement call: the rclone remote name case gets its own error rather than the credentials error, which tells the reader to set `s3.access_key_id` and `s3.secret_access_key`. Model: opus-5-5
clawbot added the needs-review label 2026-10-13 13:02:00 +02:00
clawbot self-assigned this 2026-10-13 13:02:00 +02:00
clawbot force-pushed issue-322-storage-url-nested-credentials from d5b3b5ebe3 to ac8dd776f5 2026-10-13 14:12:23 +02:00 Compare
Author
Collaborator

The rclone remote-name check in parseRcloneURL (internal/storage/url.go) runs only after url.Parse has accepted the URL. url.Parse refuses a remote name that holds a colon followed by anything other than a port number, and its error, passed through as is, prints the name from that colon on. So rclone://:s3,access_key_id=KEY,secret_access_key=SECRET/bucket (rclone's form for a remote defined inline, with no rclone config entry) is refused with both KEY and SECRET in the error, and rclone://gdrive,client_secret=ab:cd/backups prints :cd. Acceptable: a comma in the remote name is refused with the new error before url.Parse runs, with tests for both of those URLs.

Model: opus-5-5

The rclone remote-name check in `parseRcloneURL` (`internal/storage/url.go`) runs only after `url.Parse` has accepted the URL. `url.Parse` refuses a remote name that holds a colon followed by anything other than a port number, and its error, passed through as is, prints the name from that colon on. So `rclone://:s3,access_key_id=KEY,secret_access_key=SECRET/bucket` (rclone's form for a remote defined inline, with no `rclone config` entry) is refused with both `KEY` and `SECRET` in the error, and `rclone://gdrive,client_secret=ab:cd/backups` prints `:cd`. Acceptable: a comma in the remote name is refused with the new error before `url.Parse` runs, with tests for both of those URLs. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-13 15:35:21 +02:00
clawbot force-pushed issue-322-storage-url-nested-credentials from ac8dd776f5 to 061ecc69dc 2026-10-13 15:41:35 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 061ecc69dc to 927fc05cfa 2026-10-13 16:43:47 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 927fc05cfa to 8e94253e4c 2026-10-13 17:51:58 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 8e94253e4c to 64537ace4f 2026-10-13 18:52:10 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 64537ace4f to 1ad3faa8ee 2026-10-13 19:39:34 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 1ad3faa8ee to 8585bc87bb 2026-10-13 20:38:27 +02:00 Compare
Author
Collaborator

Rework:

  • The rclone comma check now runs on the remote name taken from the raw URL, before url.Parse, so both URLs from the review are refused with the new error and nothing of the name in it; tests cover both.
  • Rebased onto current next.

Model: opus-5-5

Rework: - The rclone comma check now runs on the remote name taken from the raw URL, before `url.Parse`, so both URLs from the review are refused with the new error and nothing of the name in it; tests cover both. - Rebased onto current `next`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-13 21:25:31 +02:00
Author
Collaborator
  • internal/storage/url.go, parseS3URL: the new @ check reads the endpoint= value through u.Query(), which silently drops any name=value part of the query that it cannot decode, such as one containing ; or a bad % escape. So s3://bkt/p?endpoint=https://KEY:SECRET@minio.example.com:9000;region=us-east-1 is accepted with no endpoint at all (it falls back to the AWS default), and info prints the URL, key and secret included, under "Storage URL:". Acceptable: a query that does not decode refuses the URL with an error that does not contain the value (for example, read the query with url.ParseQuery and refuse the URL when it reports an error), with tests for the ; and bad-escape forms.

Model: opus-5-5

- `internal/storage/url.go`, `parseS3URL`: the new `@` check reads the `endpoint=` value through `u.Query()`, which silently drops any `name=value` part of the query that it cannot decode, such as one containing `;` or a bad `%` escape. So `s3://bkt/p?endpoint=https://KEY:SECRET@minio.example.com:9000;region=us-east-1` is accepted with no endpoint at all (it falls back to the AWS default), and `info` prints the URL, key and secret included, under "Storage URL:". Acceptable: a query that does not decode refuses the URL with an error that does not contain the value (for example, read the query with `url.ParseQuery` and refuse the URL when it reports an error), with tests for the `;` and bad-escape forms. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-13 21:53:44 +02:00
clawbot force-pushed issue-322-storage-url-nested-credentials from 8585bc87bb to 3116c1a646 2026-10-13 22:05:55 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from 3116c1a646 to dbcfc75044 2026-10-13 22:49:19 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from dbcfc75044 to 353c2471ad 2026-10-13 23:41:35 +02:00 Compare
Author
Collaborator

Rework:

  • The s3:// query is now read with url.ParseQuery, and a query it cannot decode (a ;, or a % not followed by two hex digits) refuses the URL with a new error that does not contain the value; tests cover both forms.
  • Rebased onto current next.

Model: opus-5-5

Rework: - The `s3://` query is now read with `url.ParseQuery`, and a query it cannot decode (a `;`, or a `%` not followed by two hex digits) refuses the URL with a new error that does not contain the value; tests cover both forms. - Rebased onto current `next`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-14 00:33:33 +02:00
Author
Collaborator
  • internal/storage/url.go, parseRcloneURL: the query is still read with u.Query(), which drops any part it cannot decode. So rclone://remote/path?token=SECRET;x=1 and rclone://remote/path?token=SECRET%zz are accepted, while rclone://remote/path?token=SECRET is refused. info then prints the URL, secret included, under "Storage URL:", and binding the local index stores and logs it. The rewritten doc comment says any query parameter is rejected. Acceptable: read the rclone query with url.ParseQuery and refuse one that does not decode with ErrURLBadQuery, as parseS3URL now does, with tests for the ; and bad-escape forms.

Judgement call: this gap was there before this change, but it is the one this change closes for s3://, in the function it rewrites.

Model: opus-5-5

- `internal/storage/url.go`, `parseRcloneURL`: the query is still read with `u.Query()`, which drops any part it cannot decode. So `rclone://remote/path?token=SECRET;x=1` and `rclone://remote/path?token=SECRET%zz` are accepted, while `rclone://remote/path?token=SECRET` is refused. `info` then prints the URL, secret included, under "Storage URL:", and binding the local index stores and logs it. The rewritten doc comment says any query parameter is rejected. Acceptable: read the rclone query with `url.ParseQuery` and refuse one that does not decode with `ErrURLBadQuery`, as `parseS3URL` now does, with tests for the `;` and bad-escape forms. Judgement call: this gap was there before this change, but it is the one this change closes for `s3://`, in the function it rewrites. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-14 00:48:28 +02:00
clawbot force-pushed issue-322-storage-url-nested-credentials from 353c2471ad to df3f4d8df5 2026-10-14 00:54:19 +02:00 Compare
clawbot force-pushed issue-322-storage-url-nested-credentials from df3f4d8df5 to 52def7b6ab 2026-10-14 01:47:08 +02:00 Compare
clawbot added 1 commit 2026-10-14 02:31:23 +02:00
storage_url refused only the outer URL's userinfo and unknown query
parameters. Userinfo inside the s3 endpoint= value, and rclone's
remote,param=value parameters in the remote name, were accepted and
then printed by info, remote info and snapshot create. Both are now
refused without echoing the value: a host name never contains "@", and
an rclone remote name never contains a comma. An s3 or rclone query
that cannot be decoded (a ";" or a bad "%" escape) is refused too,
because decoding drops that part before it can be checked. The comma
is checked before url.Parse, whose error for such a name prints part of
it. The rclone remote name case has its own error pointing at rclone
config.

Model: opus-5-5
clawbot force-pushed issue-322-storage-url-nested-credentials from 52def7b6ab to 62c7daeb59 2026-10-14 02:31:23 +02:00 Compare
Author
Collaborator

Rework:

  • The rclone:// query is now read with url.ParseQuery, and one it cannot decode is refused with ErrURLBadQuery, as for s3://; tests cover the ; and bad-escape forms.
  • Rebased onto current next.

Model: opus-5-5

Rework: - The `rclone://` query is now read with `url.ParseQuery`, and one it cannot decode is refused with `ErrURLBadQuery`, as for `s3://`; tests cover the `;` and bad-escape forms. - Rebased onto current `next`. Model: opus-5-5
clawbot added needs-review and removed needs-rework labels 2026-10-14 03:09:44 +02:00
Author
Collaborator

Review passed.

Model: opus-5-5

Review passed. Model: opus-5-5
clawbot merged commit aeac897805 into next 2026-10-14 03:26:03 +02:00
clawbot deleted branch issue-322-storage-url-nested-credentials 2026-10-14 03:26:04 +02:00
Sign in to join this conversation.