Repository navigation
Description
Affected layers
- Backend (
server/): affected. The two monitoring proxies inserver/src/index.ts, mounted at/translator-apiand/jdc-api, andfetchMonitoringJson, which reads the monitoring APIs for the Telegram activity snapshot, callfetchwith its default redirect handling. A 3xx answer from the monitoring peer makes the backend request whatever itsLocationnames, on any host or port, before any status, type or size check runs. The monitoring schema copied from sv2-apps (shared/openapi.json) documents only 200 and 404 answers, so a healthy monitoring server never redirects; the defect is in sv2-ui following a redirect, not in sv2-apps. - Frontend (
src/): not affected.src/hooks/usePoolData.tsrequests the proxied paths on the UI origin; the backend follows the redirect itself and the browser never sees it. shared/: not affected. It holds the monitoring ports and the schema.
Problem
A monitoring peer that answers with a redirect to another host or port makes the backend send a request there. The dashboard triggers it through the proxies every few seconds while it is open. When Telegram alerts are paired and enabled, the backend's own Telegram check triggers it every 5 seconds with no browser at all. Reproduced on main at 828dad4 with the Loupe test under Node 24: each of the three readers sent one request to a second local server.
Impact
Whoever controls a monitoring peer, in practice a compromised mining container, can make the backend send GET requests to destinations of their choice, including addresses the mining containers cannot reach themselves, such as the backend's own loopback. The requests carry no cookie or credential, and they are blind: the answer goes to the operator's dashboard, or into Telegram messages to the paired chat, never back to the attacker. Harm therefore needs a service that acts on an unauthenticated GET and is reachable only from the backend. None was found in the documented deployments. On the backend's loopback only sv2-ui itself listens, and its state-changing routes need POST and a session. The Docker socket is a Unix socket that fetch cannot reach, and the GET endpoints of a Docker daemon configured over TCP only read. When the backend runs on the host, as npm run dev does, its loopback is the host's, where other local services may listen. Loupe rates it medium.
Expected outcome
- A monitoring read, through either proxy or for the Telegram snapshot, only ever contacts the monitoring service it was addressed to. A redirect answer is treated as a failed read: the proxy answers with an error, and the Telegram snapshot treats that source as unavailable, as it does for any other failed read.
- With a healthy monitoring server, which never redirects, the dashboard and the Telegram alerts behave as they do today.
Loupe findings
- project-loupe/audit-sv2-ui#109: the proxies and the Telegram monitoring reader follow redirects from the monitoring peer to any destination
Related issues and PRs
- http-boundary: a monitoring proxy response never renders as a page on the UI origin #308 and http-boundary: a monitoring proxy forwards at most a bounded response body #397 cover the same two proxy handlers, for the content type they forward and the body size they buffer; the three defects sit in the same code.
- Add Experimental Telegram integration to get notifications (block found, best diff, workers connections) #228 added the Telegram activity snapshot, whose reader repeats the proxies' redirect handling while already bounding the body size.
- Tracker: [Tracker] Request origin and HTTP boundary #369.
Activity