artifact downloads need SSRF and transfer hardening #3

Open
opened 2026-04-09 04:29:01 +00:00 by harivansh-afk · 0 comments

The artifact download path currently trusts arbitrary HTTP(S) URLs and streams them with the default client straight into host storage.

What happens today:

  • validateDownloadURL only checks that the URL is HTTP(S) and has a non-empty host; it does not reject loopback, link-local, RFC1918, metadata-service, or redirect-to-private targets (internal/daemon/files.go:429-444).
  • downloadFile uses http.DefaultClient with no explicit timeout, no redirect policy, no response size cap, and no checksum or digest enforcement before writing bytes to disk (internal/daemon/files.go:93-145).
  • Artifacts are cached purely by hashing the two URLs, so mutable URLs are silently pinned forever once fetched (internal/daemon/files.go:42-45, internal/daemon/create.go:194-230).

Impact:

  • A caller can direct the host daemon to fetch from sensitive local or private endpoints if this API boundary ever expands beyond fully trusted callers.
  • Slow or unbounded responses can hang create flows or exhaust disk.
  • Mutable artifact URLs can serve new content upstream while the host silently reuses stale local bytes forever.

Expected behavior:

  • Enforce a hardened fetch policy for artifacts: deny private and loopback targets, including redirects, set request and total-transfer limits, and require an integrity mechanism for cache safety.

Suggested follow-up:

  • Replace http.DefaultClient with a dedicated client that has timeout, redirect, and transport controls.
  • Resolve and reject private or loopback IPs for direct and redirected targets.
  • Bound artifact size before committing to disk.
  • Tie artifact cache reuse to immutable digests instead of URL strings alone.
The artifact download path currently trusts arbitrary HTTP(S) URLs and streams them with the default client straight into host storage. What happens today: - `validateDownloadURL` only checks that the URL is HTTP(S) and has a non-empty host; it does not reject loopback, link-local, RFC1918, metadata-service, or redirect-to-private targets (`internal/daemon/files.go:429-444`). - `downloadFile` uses `http.DefaultClient` with no explicit timeout, no redirect policy, no response size cap, and no checksum or digest enforcement before writing bytes to disk (`internal/daemon/files.go:93-145`). - Artifacts are cached purely by hashing the two URLs, so mutable URLs are silently pinned forever once fetched (`internal/daemon/files.go:42-45`, `internal/daemon/create.go:194-230`). Impact: - A caller can direct the host daemon to fetch from sensitive local or private endpoints if this API boundary ever expands beyond fully trusted callers. - Slow or unbounded responses can hang create flows or exhaust disk. - Mutable artifact URLs can serve new content upstream while the host silently reuses stale local bytes forever. Expected behavior: - Enforce a hardened fetch policy for artifacts: deny private and loopback targets, including redirects, set request and total-transfer limits, and require an integrity mechanism for cache safety. Suggested follow-up: - Replace `http.DefaultClient` with a dedicated client that has timeout, redirect, and transport controls. - Resolve and reject private or loopback IPs for direct and redirected targets. - Bound artifact size before committing to disk. - Tie artifact cache reuse to immutable digests instead of URL strings alone.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: getcompanion-ai/computer-host#3
No description provided.