mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-10-13 16:57:24 +08:00
* feat(security): add a whitelist-only outbound mode that refuses before DNS A penetration test of a private deployment found that a host outside SSRF_WHITELIST still produces a DNS query: every outbound guard resolves the name first and judges the addresses afterwards, which is what makes it immune to DNS rebinding, but it also means an attacker-chosen name reaches the resolver and can carry data out of an otherwise offline network (#3378). SSRF_DNS_WHITELIST_ONLY makes the whitelist the whole egress policy, and the check is placed wherever a name is still in hand. Where a URL is available, CheckSSRFWhitelistOnly refuses a host the whitelist does not name, IP literals included: URL validation, the sandbox outbound policy, and the web-fetch target resolver. Where only a dial address is available, CheckDialWhitelistOnly judges hostnames and leaves addresses to the checks that already exist, because an IP arriving at a dialer is either a name something else resolved or a literal the URL layer already refused. That covers the shared SSRF-safe dialer, the web-fetch dialer, the Yunzhijia webhook dialer, and every sandbox transport: the HTTP and websocket data planes, the guarded transport and the Docker engine now share one GuardedDialContext instead of each building its own dialer. Where the client resolves its own target, the name is judged before the client exists. gRPC's resolver runs before any dialer it was given, so the env-configured qdrant and milvus clients are built through small constructors that refuse a non-whitelisted host outright; a whitelisted one is resolved by gRPC as before. docreader enforces the same switch in its own validator, and compose passes the variable to both services. Matching is by name only in this mode: the whitelist's CIDR entries still match an IP literal, but a hostname is no longer resolved to see whether its addresses fall inside one, because that lookup is the query the mode exists to prevent. The value is parsed with ParseBool, and a non-empty value that parses as neither enables the mode: silently leaving an egress lockdown off because an operator wrote "yes" is the one failure mode a security control must not have. Still not covered, and documented as such: the Langfuse OTLP exporter builds its own client and never reaches these guards; and with HTTP(S)_PROXY set the proxy host is dialled unguarded when the dial address equals the proxy URL's host exactly, while a mismatch makes the proxy host itself subject to the whitelist. The switch defaults to off, so nothing changes for deployments that do not set it. * docs(security): document SSRF_DNS_WHITELIST_ONLY in website-docs docs/ has been retired in favour of website-docs/ (#3580), so the notes that lived in docs/QA.md move to the configuration table: the new switch, what to whitelist before turning it on, and the three outbound paths it still does not cover. The existing SSRF_WHITELIST row was also stale: compose gives only the app its SSRF_WHITELIST_EXTRA default (which now includes minio), and docreader's is empty, so "shared by app and docreader" held for SSRF_WHITELIST alone.