This guide is for operators running fetchkit in shared clusters, AI agent data planes, or other environments where untrusted users can influence fetched URLs.
fetchkit can harden its own outbound fetch path:
- blocks private and reserved IP ranges by default
- revalidates every redirect hop
- pins DNS to the validated IP to reduce DNS rebinding risk
- ignores
HTTP_PROXY,HTTPS_PROXY, andNO_PROXYby default - can block internal hostnames before DNS resolution
- can restrict outbound traffic to an allowed port set
- can restrict redirects to the original host only
Use the hardened profile for cluster-facing deployments:
use fetchkit::{FetchRequest, Tool};
let tool = Tool::builder()
.hardened()
.allow_prefix("https://docs.example.com")
.build();
let response = tool
.execute(FetchRequest::new("https://docs.example.com").as_markdown())
.await?;The hardened profile does all of this:
- keeps private IP blocking enabled
- ignores ambient proxy environment variables
- allows only ports
80and443 - blocks
localhost,.local,.internal,.svc, and.cluster.local - only follows same-host redirects
CLI and MCP equivalents:
fetchkit fetch https://example.com --hardened
fetchkit mcp --hardenedfetchkit cannot guarantee that the pod, container, or VM itself has no internal network reachability. If the runtime can open arbitrary sockets to internal services, an infrastructure mistake can still expose that path outside of fetchkit.
Treat library checks as defense in depth, not the only boundary.
For cluster deployments, use both application policy and network policy:
- Run
fetchkitin a dedicated namespace or workload class. - Deny direct egress from
fetchkitexcept to DNS and a dedicated egress proxy. - Make the egress proxy the only component allowed to reach the public Internet.
- Block RFC1918 ranges, cluster pod/service CIDRs, link-local ranges, loopback, and metadata endpoints at the proxy or network layer.
- Keep
fetchkithardening enabled inside the application.
This gives you two independent checks:
fetchkitrejects obviously unsafe targets before dialing.- the network path still cannot reach internal addresses if application policy is bypassed or misconfigured.
By default, fetchkit ignores HTTP_PROXY, HTTPS_PROXY, and NO_PROXY. This is intentional. In cluster environments, inherited proxy variables can silently route requests around your expected enforcement path.
Only opt in to proxy environment variables if that proxy is part of your intended design:
let tool = Tool::builder()
.hardened()
.respect_proxy_env(true)
.build();fetchkit fetch https://example.com --hardened --allow-env-proxyIf you need a proxy, prefer a dedicated egress proxy with explicit policy over ambient proxy settings that every process inherits.
For Internet-facing fetching from untrusted input:
- keep
block_private_ips(true) - use
.hardened() - add
allow_prefix(...)if you know the domains ahead of time - keep
same_host_redirects_only(true)unless cross-host redirects are required - only opt in to
respect_proxy_env(true)when the proxy is deliberate and hardened
If you must fetch nonstandard ports or internal-looking public domains, start from .hardened() and then add the narrowest exception you need.