Ssrf in Chi with Mutual Tls
Ssrf in Chi with Mutual Tls — how this specific combination creates or exposes the vulnerability
Server-Side Request Forgery (SSRF) in Chi with Mutual TLS (mTLS) involves a scenario where an authenticated service or client can cause the server to make unintended requests to internal or external endpoints, even though mTLS is in place. mTLS ensures both the client and server present valid certificates, which typically restricts who can initiate a connection. However, SSRF can still manifest when the server-side application acts as a proxy or when client certificates are obtained and misused within the application logic.
In Chi, this often occurs when developers build custom HTTP clients that forward requests based on user input without adequate validation. For example, if an endpoint accepts a URL parameter and uses a http.Client with a custom Transport that includes a client certificate, an attacker might supply an internal address like http://169.254.169.254/latest/meta-data/ (AWS metadata service) or an internal Kubernetes service. Even with mTLS protecting the perimeter, the server’s outbound request may not enforce the same strict network segmentation, allowing the SSRF to reach internal services that trust the server’s certificate.
The risk is amplified when the server’s mTLS configuration does not restrict outbound destinations. The server certificate is trusted by internal services, so requests originating from the server are accepted. If the application does not validate the target host, port, or scheme, an attacker can pivot from the exposed endpoint to internal systems, bypassing network-level mTLS restrictions that were designed only for inbound connections. This combination of mTLS for authentication and SSRF for request manipulation creates a path where the server’s trusted identity is leveraged to access protected internal resources.
Real-world patterns include APIs that accept a target host for health checks or webhook delivery, where the developer assumes mTLS is sufficient. In Chi, a route might use middleware to load client certificates dynamically, but if the target URL is user-supplied without host allowlisting, the mTLS protection does not prevent the malicious request from reaching unintended endpoints. Tools like middleBrick can detect such misconfigurations by scanning the unauthenticated attack surface and identifying endpoints that accept URLs without proper validation, even when mTLS is present.
Mutual Tls-Specific Remediation in Chi — concrete code fixes
Remediation focuses on strict input validation, network controls, and certificate usage. Below are concrete examples using Chi and Go’s http.Transport to enforce safe outbound requests while preserving mTLS.
1. Allowlist Hosts in HTTP Client
Create a custom RoundTripper that validates the request URL against an allowlist before proceeding. This prevents SSRF by ensuring only approved domains or IPs are reachable.
import (
"crypto/tls"
"net/http"
"strings"
)
func allowlistTransport(allowedHosts []string, baseTransport http.RoundTripper) http.RoundTripper {
return &allowlistRoundTripper{
allowedHosts: allowedHosts,
base: baseTransport,
}
}
type allowlistRoundTripper struct {
allowedHosts []string
base http.RoundTripper
}
func (t *allowlistRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
host := req.URL.Hostname()
for _, allowed := range t.allowedHosts {
if host == allowed {
return t.base.RoundTrip(req)
}
}
return nil, &urlError{err: "host not allowed", url: req.URL.String()}
}
// Usage in Chi route
func healthCheckHandler(client *http.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Use client with allowlist transport
resp, err := client.Get("https://" + r.URL.Query().Get("host"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer resp.Body.Close()
w.WriteHeader(resp.StatusCode)
}
}
2. Enforce mTLS with Restricted Certificates
Configure the server and client to use specific certificates and verify peer identities strictly. In Chi, you can set up a TLS configuration that pins client certificates and disables insecure options.
func secureClientCert(certFile, keyFile, caCert string) (*http.Client, error) {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
rootCAs, err := os.ReadFile(caCert)
if err != nil {
return nil, err
}
certPool := x509.NewCertPool()
certPool.AppendCertsFromPEM(rootCAs)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: certPool,
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
}
transport := &http.Transport{
TLSClientConfig: tlsConfig,
}
return &http.Client{Transport: transport}, nil
}
3. Validate and Restrict Outbound Targets
Ensure that any user-provided URL is parsed and validated for scheme, host, and port. Reject private IP ranges and localhost unless explicitly required and safe.
import (
"net"
"net/url"
)
func isValidTarget(rawURL string) bool {
parsed, err := url.Parse(rawURL)
if err != nil || parsed.Scheme != "https" {
return false
}
ip := net.ParseIP(parsed.Hostname())
if ip != nil && (ip.IsPrivate() || ip.IsLoopback()) {
return false
}
return true
}
Combine these techniques in Chi routes to ensure that even with mTLS, SSRF risks are minimized. middleBrick scans can help identify endpoints that accept untrusted URLs despite mTLS, providing findings with severity and remediation guidance.
Related CWEs: ssrf
| CWE ID | Name | Severity |
|---|---|---|
| CWE-918 | Server-Side Request Forgery (SSRF) | CRITICAL |
| CWE-441 | Unintended Proxy or Intermediary (Confused Deputy) | HIGH |