Skip to content

fix(storage): let callers refuse endpoint overrides in a tenant's DSN - #266

Merged
ChiragAgg5k merged 1 commit into
mainfrom
fix/storage-untrusted-dsn
Oct 29, 2026
Merged

ChiragAgg5k merged 1 commit into
mainfrom
fix/storage-untrusted-dsn

Conversation

@ChiragAgg5k

@ChiragAgg5k ChiragAgg5k commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

The url and insecure DSN parameters replace the host a DSN names. Operators set them deliberately: Appwrite's self-hosted docs and CI use s3://…@localhost?…&url=http%3A%2F%2Fminio%3A9000, and so does this README. A DSN built from a tenant's values can carry them too: with s3://AK:SK@{endpoint}/{bucket} spliced together, a bucket of b?url=http://169.254.169.254/latest&insecure=true redirects every request to the metadata service.

Change

getDevice() takes bool $trusted = true. With trusted: false:

  • a DSN with a url or insecure parameter is refused, so the host the caller checked is the host reached;
  • an empty, file:// or local:// connection is refused instead of resolving to the local filesystem.

The default is unchanged, so existing callers and operator DSNs behave as before. Callers pass trusted: false for stores a tenant configures.

Related: appwrite/appwrite#15066 adds DSN::from(), which encodes each part, so spliced values can't add parameters in the first place. This PR is the backstop for DSNs already stored as strings.

Tests

StorageFactoryTest:

  • untrusted DSNs carrying url, insecure, a url spliced in through the bucket, a local or file scheme, an empty string or null are refused;
  • an untrusted DSN without overrides still reaches its own host and port.

Pint, PHPStan and Rector pass on the changed files.

The url and insecure parameters replace the host a DSN names. An operator sets them on purpose, but a DSN holding tenant values could carry them through a spliced bucket and send every request to an address the tenant chose (appwrite-labs/cloud#6857). getDevice(trusted: false) refuses them, and the local device, so the host the caller checked is the one reached.
@ChiragAgg5k
ChiragAgg5k merged commit 2435f2e into main Oct 29, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants