* fix(backend): validate the S3 endpoint host before the restore download
downloadFileFromS3() built an S3StorageAdapter and called .download()
directly, skipping the isHostAllowed() private-IP/DNS-rebinding guard
that testConnection() applies elsewhere — an admin with backup.restore
could point the configured S3 endpoint at an internal/metadata address
for unauthenticated egress via the server.
Backport of 89c6a673bf from main
(GHSA-vm2x-c628-3cx5) to stable; cherry-picked cleanly, no adaptation
needed.
* fix(backend): pin the restore S3 download to its validated DNS resolution
isHostAllowed() was check-then-connect: the AWS SDK re-resolves the
endpoint hostname independently when it actually connects, so a DNS
rebinding condition between the preflight check and the real
connection could still reach a private/internal address.
Stable didn't yet have the pinnedRequestOptions() primitive main's
webhookDeliveryWorker.js uses for this, so it's ported here as
utils/pinnedRequest.js, plus an additive
validateExternalUrlWithAddresses() in networkValidation.js that
returns the resolved address set (existing exports/behavior
untouched). Both get wired into the S3Client's requestHandler for the
restore download path only.
---------
Co-authored-by: Paul Nothaft <[email protected]>