Internal Network Pivot
From the vulnerable app server to every internal service. Redis, Elasticsearch, internal dashboards, Kubernetes API — that the attacker cannot reach directly but the server can.
From the vulnerable app server to every internal service. Redis, Elasticsearch, internal dashboards, Kubernetes API — that the attacker cannot reach directly but the server can.
Once an attacker finds an SSRF, the internal network becomes the attack surface. The server can reach Redis, Elasticsearch, Kubernetes API servers, internal dashboards, and database ports that are invisible from the public internet. SSRF is rarely the end of the exploit chain — it is the pivot point into deeper infrastructure.
Cloud metadata is the most famous SSRF target, but the internal network contains far more services. Redis runs on port 6379, often without authentication. Elasticsearch listens on 9200, frequently with no access control. Kubernetes API servers listen on 6443 (or 443) and may accept unauthenticated requests if misconfigured. Internal dashboards, Jenkins servers, Prometheus exporters, and database replicas all listen on private IPs that the server can reach.
The critical technique is protocol smuggling. SSRF is usually associated with HTTP, but many URL-fetching libraries support multiple protocols: gopher://, dict://, file://, and ftp://. The gopher:// protocol is especially dangerous because it sends raw bytes over TCP, letting the attacker craft arbitrary Redis, SMTP, or Memcached commands by encoding them in the URL path.
Redis is the most common gopher:// target because it uses a line-based protocol. A gopher URL like gopher://redis:6379/_SET%20backdoor%20%22ssh-rsa%20...%22 sends the SET command to Redis over TCP, bypassing the lack of HTTP support. This technique works because the URL-fetching library opens a raw TCP connection to the destination and sends the gopher payload as the initial data.
The tool below simulates an SSRF pivot into internal services. Enter a hostname and port (e.g. redis:6379) to see what happens when the server reaches that service. Toggle safe mode to see how a network allowlist blocks all non-approved destinations.
Enter a host:port to probe internal services via SSRF.
No internal requests yet.
In 2020, security researchers disclosed an SSRF vulnerability in Shopify that used the gopher:// protocol to inject commands into an internal Redis cache. Shopify ran a URL-fetching feature that supported the gopher:// protocol. By encoding Redis commands in the gopher URL, the attacker could write arbitrary keys to the Redis cache. Since some Shopify components deserialised data from Redis, the attacker achieved remote code execution on the application server.
The attack chain was: SSRF via URL fetcher to gopher:// to Redis port 6379 to write a malicious serialised object to a Redis key to trigger deserialisation in a component that reads from Redis for remote code execution. Each step used a feature that was individually reasonable — URL fetching, gopher support, Redis caching — but together they created a full compromise chain. Shopify fixed the issue by removing gopher:// support from their URL fetcher and adding Redis authentication.
The most important defence is network segmentation. Application servers that need to fetch URLs should be in a separate network segment with egress rules that allow only specific destinations. Redis, Elasticsearch, and Kubernetes APIs should require authentication even on internal networks.
// VULNERABLE - allows gopher:// protocol
const url = new URL(userInput);
const res = await fetch(url); // gopher:// sends raw bytes
// SAFE - restrict to HTTP/HTTPS only
const SAFE_PROTOCOLS = ['http:', 'https:'];
const url = new URL(userInput);
if (!SAFE_PROTOCOLS.includes(url.protocol)) {
throw new Error('unsupported protocol');
}
const resolvedIp = await resolveHostname(url.hostname);
if (!ALLOWED_IPS.includes(resolvedIp)) {
throw new Error('destination not in allowlist');
}
const res = await fetch(url.href);
// SAFE - network segmentation (infrastructure)
// Kubernetes NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
spec:
podSelector: { matchLabels: { app: url-fetcher } }
egress:
- to:
- ipBlock: { cidr: 10.0.1.0/24 }
ports: [{ port: 443 }]Audit URL-fetching libraries for protocol support. Libraries like curl, requests, and Ruby's open-uri support gopher://, dict://, and file:// by default. Restrict to HTTP and HTTPS only. Apply network policies (Kubernetes NetworkPolicy, AWS Security Groups, GCP Firewall Rules) that deny egress to internal services from SSRF-vulnerable tiers. Enable authentication on Redis, Elasticsearch, and databases — internal networks are no longer trusted.
1.Why is the gopher:// protocol so dangerous in an SSRF context?
2.What makes Redis the most common internal SSRF target?
3.What is the most effective defence against SSRF internal pivoting?