A bounded fetch tool, where the allowlist is the feature #426

Closed
opened 2026-08-13 12:38:02 +00:00 by coilyco-ops · 0 comments
Member

Slice of #412, where Kai asked for "a simple http request-y thing, a curl-y thing" and correctly guessed plain stdlib.

Scope

An HTTPS GET the model can call, bounded by a deployment-supplied host allowlist. net/http, no dependency.

Why the allowlist is the feature and the fetching is the easy part

The fetch runs inside the cluster. Unbounded it reaches the tailnet, other services' internal endpoints, and cloud metadata addresses — and the model is exactly the component an attacker gets to talk to. A tool that fetches any URL a model can be persuaded to fetch is server-side request forgery with a conversational interface.

Five bounds

  • Exact host match, not suffix. eco-app.coilysiren.me.evil.example is a different host and registering it costs an attacker nothing.
  • HTTPS only.
  • Private addresses refused at dial time, not by reading the URL. This is the one that is easy to get wrong: an allowlisted name can resolve to an internal address and a hostname check never sees it.
  • Redirects refused. A redirect is a second destination the allowlist never saw.
  • Size cap and timeout. A large body becomes prompt; a slow host spends the turn.

Empty allowlist offers no tool at all — no schema, no prompt mention, nothing to be talked into.

GET only

A curl-shaped tool that reads is most of what was asked for. One that writes is a different authority and should be requested on its own terms.

Out of scope

What a fetched page says. The allowlist bounds where text comes from and not what it contains, so an approved host serving hostile instructions is still open. That is the same boundary web search raises on #177 and belongs with it.

Acceptance

  • No allowlist offers no tool and serves no call.
  • Suffix and prefix lookalikes, plain http, non-http schemes, cluster service names, and the metadata address are all refused.
  • Loopback, private, link-local and unspecified addresses are refused at dial time; a public address is not.
**Slice of** https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/412, where Kai asked for *"a simple http request-y thing, a curl-y thing"* and correctly guessed plain stdlib. ## Scope An HTTPS GET the model can call, bounded by a deployment-supplied host allowlist. `net/http`, no dependency. ## Why the allowlist is the feature and the fetching is the easy part The fetch runs **inside the cluster**. Unbounded it reaches the tailnet, other services' internal endpoints, and cloud metadata addresses — and the model is exactly the component an attacker gets to talk to. A tool that fetches any URL a model can be persuaded to fetch is server-side request forgery with a conversational interface. ## Five bounds - **Exact host match**, not suffix. `eco-app.coilysiren.me.evil.example` is a different host and registering it costs an attacker nothing. - **HTTPS only.** - **Private addresses refused at dial time**, not by reading the URL. This is the one that is easy to get wrong: an allowlisted name can resolve to an internal address and a hostname check never sees it. - **Redirects refused.** A redirect is a second destination the allowlist never saw. - **Size cap and timeout.** A large body becomes prompt; a slow host spends the turn. **Empty allowlist offers no tool at all** — no schema, no prompt mention, nothing to be talked into. ## GET only A curl-shaped tool that reads is most of what was asked for. One that writes is a different authority and should be requested on its own terms. ## Out of scope **What a fetched page says.** The allowlist bounds where text comes from and not what it contains, so an approved host serving hostile instructions is still open. That is the same boundary web search raises on https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/177 and belongs with it. ## Acceptance - No allowlist offers no tool and serves no call. - Suffix and prefix lookalikes, plain http, non-http schemes, cluster service names, and the metadata address are all refused. - Loopback, private, link-local and unspecified addresses are refused at dial time; a public address is not.
Sign in to join this conversation.
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
coilyco-gaming/sirens-echo#426
No description provided.