T0: SSRF deny-dialer, prompt-injection envelope, real client-IP resolution, two-tier rate limiting - #53
Open
andreimarinescu wants to merge 1 commit into
Open
T0: SSRF deny-dialer, prompt-injection envelope, real client-IP resolution, two-tier rate limiting#53andreimarinescu wants to merge 1 commit into
andreimarinescu wants to merge 1 commit into
Conversation
…pe, client IP, rate limiting) Closes the T0 scope of the public-launch plan. T0.1 gates the grounded topic->URL resolver, the first feature that lets users influence crawling. netguard: a net.Dialer.Control hook refusing non-global-unicast resolved addresses, applied to the crawler transport and the server-side fetchers in serve_crawl.go, fetchone.go and cmd_crawl.go. The embed, chat, rerank, chatgate and peer-forward clients are exempt: they legitimately dial private endpoints, and on prod the chat endpoint is a box-local vLLM. Rejection set ported from the harvesters' resolve.py, including 6to4 and Teredo recursion. Guarded by crawler.block_private_networks, default on, with COSIFT_ALLOW_PRIVATE_NETWORKS as the override. A source-scanning test fails when a new unguarded egress appears. VetTargets covers the proxy-pool path, where Control never sees the target. promptsafe: crawled text is fenced with a per-request nonce at thirteen prompt construction sites, and the user question moved out of the attacker-controlled region. The [N] citation token is deliberately unchanged -- cmd_eval.go parses it for the grounding metric. Covers the planner's getSiteTitles input and the research refine loop's lastAnswer re-injection. rate limiting: the per-IP limiter keyed on RemoteAddr, which behind Caddy is always 127.0.0.1, and that address is whitelisted -- so it was inert, not merely mis-keyed. clientIPResolver is exported and wired in; feedback.go no longer trusts the leftmost forwarded hop and querylog.go no longer logs the raw header. Adds a tighter always-on LLM tier over /answer, /research, /query and /find, plus /search and /find_similar when they opt into rerank or expand. A key the transport does not attest may not match the operator whitelist, so a forwarded hop cannot claim 127.0.0.1. Behaviour is unchanged for on-box callers and no worse than today for proxied traffic; activating the trusted-proxy config is a separate, sequenced ops step. Verified in golang:1.25-bookworm: gofmt, vet, linux/arm64 cross-compile and go test -race ./... across 18 packages. E2E on cosift-local goes from 7 pass / 8 fail to 15 pass / 0 fail, and BM25 golden overlap@10 and @50 are both 1.0000 against control on a frozen store.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the T0 engine-hardening scope from the Cosift public-launch plan. T0.1 gates the grounded
topic→URL resolver (T6) — the first feature that lets users influence what the crawler fetches — so
this has to land before that work can start.
54 files. Three logically separate fixes, one commit each.
What was actually wrong
Reproduced on a live instance (
cosift-local, 3,070-doc store) against the v0.2.5 binary before anychange. Full output in
tools/golden/2026-09-15-t0-local/e2e-control.txtin the monorepo.The admin routes matter more than the
awrapgate suggests:peerTokenOKreturns true when theconfigured token is empty (
serve_helpers.go:36-38), and production has it empty, so these arereachable unauthenticated.
serve_crawl.go:195also uses its own client rather than the crawlertransport, so the Cloudflare Worker that fronts crawl GETs does not cover this path in production
either.
After the change: all six refused,
/feedbackspoof 21/25 limited. 6 PASS/7 FAIL → 13 PASS/0 FAIL.