A ? written into the host segment of an image URL gives another unsigned spelling of an allowlisted source #275

Open
opened 2026-10-15 12:31:47 +02:00 by clawbot · 0 comments
Collaborator

Where: internal/imgcache/urlparser.go parseImageComponents on next at c23585d: the host segment is everything before the first / of the wildcard, and only @ is refused in it; the source query is split from the path only. Found by the review of #266.

What is wrong: a ? written into the host segment as %3F reaches the parser decoded, so /v1/image/cdn.example.com%3Fx=1/a.jpg/100x100.jpg gives the host cdn.example.com?x=1. The source URL built from it is https://cdn.example.com?x=1/a.jpg, which Go reads as host cdn.example.com with the query x=1/a.jpg: the allowlist passes it, pixa fetches the host's root path with that query, and the result is cached under the host as written. Each new text after the ? is another unsigned spelling of one upstream request with its own cache keys, the problem #246 closed for letter case and ports.

How it fails: with a host allowlisted, an outsider varies the text after %3F to make pixa fetch and store the same upstream response under as many cache keys as it likes.

Severity: low

Definition of done:

  1. parseImageComponents refuses with 400 a host segment holding anything a URL host cannot hold (at least ?, #, %, \ and whitespace, besides @); a host name, an IPv4 address, a bracketed IPv6 address and a : with a port stay accepted, as #246 left them.
  2. Test first for %3F and # in the host segment; make check green.

Package: internal/imgcache.

Model: opus-5-5

Where: `internal/imgcache/urlparser.go` `parseImageComponents` on `next` at `c23585d`: the host segment is everything before the first `/` of the wildcard, and only `@` is refused in it; the source query is split from the path only. Found by the review of https://git.eeqj.de/sneak/pixa/pulls/266. What is wrong: a `?` written into the host segment as `%3F` reaches the parser decoded, so `/v1/image/cdn.example.com%3Fx=1/a.jpg/100x100.jpg` gives the host `cdn.example.com?x=1`. The source URL built from it is `https://cdn.example.com?x=1/a.jpg`, which Go reads as host `cdn.example.com` with the query `x=1/a.jpg`: the allowlist passes it, pixa fetches the host's root path with that query, and the result is cached under the host as written. Each new text after the `?` is another unsigned spelling of one upstream request with its own cache keys, the problem https://git.eeqj.de/sneak/pixa/issues/246 closed for letter case and ports. How it fails: with a host allowlisted, an outsider varies the text after `%3F` to make pixa fetch and store the same upstream response under as many cache keys as it likes. Severity: low Definition of done: 1. `parseImageComponents` refuses with 400 a host segment holding anything a URL host cannot hold (at least `?`, `#`, `%`, `\` and whitespace, besides `@`); a host name, an IPv4 address, a bracketed IPv6 address and a `:` with a port stay accepted, as https://git.eeqj.de/sneak/pixa/issues/246 left them. 2. Test first for `%3F` and `#` in the host segment; `make check` green. Package: `internal/imgcache`. Model: opus-5-5
clawbot self-assigned this 2026-10-15 12:31:47 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#275