Repository navigation
0.55.1 — inline image preview no longer fetches private addresses - #203
Merged
Merged
Conversation
buildInlineImageBlock fetched whatever image URL the gateway returned with a plain fetch(): no private-address check and automatic redirects. With inline previews on, a malicious or compromised gateway (or an upstream URL it passes through) could make the user's machine GET localhost, 169.254.169.254, or the private network. The per-hop, DNS-resolved guard already existed inline in resolveImageRef. Lift it into fetchPublicUrl in utils/ssrf.ts (http(s) only, every redirect hop re-checked, redirect bodies released) and route both callers through it. data:image URIs from image2image routes still inline without a network round-trip. Tests: private/loopback/metadata URLs are refused with zero requests made, a public URL 302ing into metadata never reaches the target, public-to-public redirects still work, file: is refused. The redirect case uses a mock that follows 3xx like real fetch, and fails on the old code. Refs #194
resolveImageRef and buildInlineImageBlock checked Content-Length, then buffered the whole body with arrayBuffer() and checked its length. A chunked response has no Content-Length, and fetch() decodes gzip/br transparently, so a few-KB brotli bomb advertised its compressed size and inflated in memory until the abort. The comment claimed this prevented an OOM in the stdio process; it only did for an honest header. readCappedBody (utils/read-capped.ts) counts decoded bytes as they arrive and cancels the stream at the cap. Both callers use it. Tests: an endless body with no Content-Length is cancelled within one chunk of the cap.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #194.
buildInlineImageBlock(src/utils/inline-image.ts) fetched the gateway-returned image URL with a plainfetch(), so there was no private-address check and redirects were followed automatically. With inline previews enabled (off by default), a malicious or compromised gateway could make the user's machine request localhost, cloud metadata, or private-network hosts.Fix. The DNS-resolved, per-hop SSRF guard already existed inline in
resolveImageRef. It moves intofetchPublicUrlinsrc/utils/ssrf.ts, and both callers now use it:data:imageURIs from image2image routes still inline locally, with no network request.Video and music poll URLs were already origin-pinned through
resolveGatewayUrl/same-origin checks. This was the only gateway-URL fetch without a guard.Tests. New cases in
test/inline-image.test.ts:file:URLs are refusedThree of the new cases fail on the old code. The
ssrf.jsmodule stubs in 5 test files gained afetchPublicUrlpassthrough. Full suite: 1429/1429 pass.tsc --noEmitis clean.