The WHOIS client reads a server's answer into memory with no size cap and follows a referral to any host and port #106

Closed
opened 2026-10-19 22:35:13 +02:00 by clawbot · 1 comment
Collaborator

Where: Client.query and parseIANAReferral in internal/whois/whois.go.

query appends every line a WHOIS server sends to a strings.Builder until the connection ends or the 30-second absolute read deadline passes; the only other bound is 64 KiB per line. The caller's one-minute context limits the dial only. Nothing limits the total. The servers reached are IANA, the five RIR servers, and whatever host:port an IANA refer: line names when it matches none of the five (used as given, :43 appended only when no port is present), all over plain TCP on port 43, so a DNS or on-path attacker can also stand in for them.

A server that keeps sending short lines fills the Go heap at line rate for up to 30 s (gigabytes on a fast path). GOMEMLIMIT is a soft limit, so the process can pass the 5 GiB container limit and be killed, losing the handlers' pending batches; on a slower path a multi-hundred-megabyte string is stored as whois_raw through the one writing connection.

Severity: low (needs a hostile, compromised or impersonated WHOIS server).

Definition of done

  • The response read is capped at a named size (a WHOIS answer is a few KiB; 1 MiB is generous) with io.LimitReader; reaching the cap is an error.
  • A refer: line is followed only to a host on port 43, or only to the known RIR servers.
  • Test, failing before the fix: a local server that streams lines at full speed for 2 s after the query; query returns an error or a string no longer than the cap (today the whole stream).
  • make check passes.

Model: fable-5-1

Where: `Client.query` and `parseIANAReferral` in `internal/whois/whois.go`. `query` appends every line a WHOIS server sends to a `strings.Builder` until the connection ends or the 30-second absolute read deadline passes; the only other bound is 64 KiB per line. The caller's one-minute context limits the dial only. Nothing limits the total. The servers reached are IANA, the five RIR servers, and whatever `host:port` an IANA `refer:` line names when it matches none of the five (used as given, `:43` appended only when no port is present), all over plain TCP on port 43, so a DNS or on-path attacker can also stand in for them. A server that keeps sending short lines fills the Go heap at line rate for up to 30 s (gigabytes on a fast path). `GOMEMLIMIT` is a soft limit, so the process can pass the 5 GiB container limit and be killed, losing the handlers' pending batches; on a slower path a multi-hundred-megabyte string is stored as `whois_raw` through the one writing connection. Severity: low (needs a hostile, compromised or impersonated WHOIS server). ## Definition of done - The response read is capped at a named size (a WHOIS answer is a few KiB; 1 MiB is generous) with `io.LimitReader`; reaching the cap is an error. - A `refer:` line is followed only to a host on port 43, or only to the known RIR servers. - Test, failing before the fix: a local server that streams lines at full speed for 2 s after the query; `query` returns an error or a string no longer than the cap (today the whole stream). - `make check` passes. Model: fable-5-1
clawbot self-assigned this 2026-10-19 22:35:13 +02:00
Author
Collaborator

Built in #128: a WHOIS answer is read up to 1 MiB, reaching that is an error, and a referral is followed only to one of the five RIR servers.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/routewatch/pulls/128: a WHOIS answer is read up to 1 MiB, reaching that is an error, and a referral is followed only to one of the five RIR servers. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#106