diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-10-28 07:56:40 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-10-28 07:56:40 +0000 |
| commit | 2c893238914b246cd3f77a20a71bc88399790cb9 (patch) | |
| tree | 68573100890e0394eb23627df17396ad7b326e0d /app | |
| parent | f2b5c8f471096ce467c0b606dfaaa88ebf46648a (diff) | |
Every outbound fetch may only reach a public address
A security review flagged the transcript download as an SSRF: the URL comes from
a <podcast:transcript> tag, so a publisher chooses it. It was the third place
with that shape, not the first -- the feed fetch takes a URL the phone sent, and
the enclosure download takes one from inside the feed, and both had been doing
it for longer. Fixing the flagged instance alone would have fixed nothing.
The exposure is specific rather than theoretical. listend listens on
127.0.0.1:38090 behind Apache on a host running other services, so a feed naming
a loopback, private or link-local address -- 169.254.169.254 among them -- would
have the server fetch something only it can reach. In the transcript case the
result would then be stored and handed to the phone as an episode's words, which
turns an internal reachability problem into a readable one.
The check runs when the connection is dialled, not when the URL is read, so it
also covers a redirect into an internal address and a hostname that resolves to
one. The address connected to is the address that was checked.
internal/safefetch now has a structural test that walks this server's own source
and refuses any production file that builds its own HTTP client or uses the
shared default. It was watched failing against a deliberately added violation
before being kept. Tests still inject a plain client through the seam each type
already had, because a httptest server is on loopback by definition -- which is
exactly what production is now refusing.
Checked against the live subscription list before committing: all 44 feeds use
https and none resolves to a private, loopback or link-local address, so nothing
Peter subscribes to is affected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'app')
0 files changed, 0 insertions, 0 deletions
