HIGH ssrf server sidechi

Ssrf Server Side in Chi

How SSRF Manifests in Chi

Server-Side Request Forgery (SSRF) in Chi manifests through HTTP handler functions that make outbound requests based on untrusted user input. Chi's router pattern, where handlers receive context and request objects, creates specific SSRF vulnerabilities when those handlers construct URLs for internal API calls, database queries, or external service integrations.

The most common SSRF pattern in Chi applications occurs when handlers accept URLs as parameters and use them to make HTTP requests. For example:

func proxyHandler(w http.ResponseWriter, r *http.Request) {
    targetURL := r.URL.Query().Get("url")
    resp, err := http.Get(targetURL) // SSRF vulnerability!
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer resp.Body.Close()
    io.Copy(w, resp.Body)
}

This pattern is particularly dangerous in Chi applications because the framework's middleware chain can mask where the vulnerability originates. A middleware might extract a URL from headers, cookies, or request bodies, then pass it to handlers that make the actual request.

Chi-specific SSRF scenarios include:

  • Service discovery endpoints that query internal microservices using URLs from request parameters
  • Webhook handlers that call back to URLs provided in webhook payloads
  • API gateway patterns where Chi routes forward requests to backend services based on path parameters
  • Configuration endpoints that read from URLs pointing to internal configuration files

The severity escalates when SSRF allows access to internal services on private networks. An attacker might exploit this to reach services on 127.0.0.1, 10.x.x.x, 172.16.x.x, or 192.168.x.x networks that aren't exposed to the internet. This can lead to database enumeration, internal API abuse, or cloud metadata service access.

Chi-Specific Detection

Detecting SSRF in Chi applications requires both static analysis and runtime scanning. Static analysis should focus on handler functions that construct HTTP requests using request-derived data. Look for patterns where URL strings are built from query parameters, headers, or JSON bodies.

middleBrick's SSRF detection for Chi applications includes:

  • URL parameter extraction from request objects
  • Outbound HTTP request construction patterns
  • Network access attempts to private IP ranges
  • Cloud metadata service endpoint probing (169.254.169.254, 169.254.170.2)
  • SSRF-specific payloads testing for blind SSRF conditions

Using middleBrick's CLI for Chi applications:

npx middlebrick scan http://your-chi-app.com/api/proxy

The scanner tests common SSRF vectors including:

http://127.0.0.1:3306 (MySQL)
http://169.254.169.254/latest/meta-data/ (AWS metadata)
http://169.254.170.2/ (ECS metadata)
http://metadata.google.internal/computeMetadata/v1/ (GCP metadata)

middleBrick's runtime scanning also checks for SSRF in OpenAPI specifications. If your Chi application serves an OpenAPI spec, middleBrick cross-references endpoint definitions with actual runtime behavior to identify discrepancies that might indicate SSRF vulnerabilities.

Manual detection should include reviewing all Chi route handlers for outbound HTTP calls. Pay special attention to handlers that:

  • Proxy requests to other services
  • Fetch external resources
  • Call webhook URLs
  • Access configuration files via URLs

Chi-Specific Remediation

Remediating SSRF in Chi applications requires a defense-in-depth approach. The most effective strategy combines input validation, allowlisting, and network-level controls.

Input validation using Go's standard library:

import (
    "net/url"
    "regexp"
)

var validURLPattern = regexp.MustCompile(`^https?://[a-zA-Z0-9.-]+(:[0-9]+)?(/.*)?$`)

func validateURL(rawURL string) (string, error) {
    if !validURLPattern.MatchString(rawURL) {
        return "", errors.New("invalid URL format")
    }
    parsed, err := url.Parse(rawURL)
    if err != nil {
        return "", err
    }
    
    // Block private IP ranges
    if isPrivateIP(parsed.Hostname()) {
        return "", errors.New("private IP addresses not allowed")
    }
    
    // Block cloud metadata services
    if isMetadataService(parsed.Hostname()) {
        return "", errors.New("metadata service access denied")
    }
    
    return parsed.String(), nil
}

func isPrivateIP(host string) bool {
    privateBlocks := []*net.IPNet{
        {IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(8, 32)},
        {IP: net.ParseIP("172.16.0.0"), Mask: net.CIDRMask(12, 32)},
        {IP: net.ParseIP("192.168.0.0"), Mask: net.CIDRMask(16, 32)},
        {IP: net.ParseIP("127.0.0.0"), Mask: net.CIDRMask(8, 32)},
    }
    ip := net.ParseIP(host)
    if ip == nil {
        return false
    }
    for _, block := range privateBlocks {
        if block.Contains(ip) {
            return true
        }
    }
    return false
}

func isMetadataService(host string) bool {
    metadataHosts := map[string]bool{
        "169.254.169.254": true,
        "169.254.170.2": true,
        "metadata.google.internal": true,
        "169.254.169.254": true,
    }
    return metadataHosts[host]
}

Using Chi's middleware for SSRF protection:

func ssrfProtection(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Check for SSRF indicators in request
        if containsSSRFIndicator(r) {
            http.Error(w, "SSRF attempt detected", http.StatusBadRequest)
            return
        }
        next.ServeHTTP(w, r)
    })
}

func containsSSRFIndicator(r *http.Request) bool {
    // Check query parameters
    q := r.URL.Query()
    for _, v := range q {
        if isSuspiciousURL(v[0]) {
            return true
        }
    }
    
    // Check headers
    for _, values := range r.Header {
        for _, v := range values {
            if isSuspiciousURL(v) {
                return true
            }
        }
    }
    return false
}

func isSuspiciousURL(input string) bool {
    // Check for common SSRF patterns
    patterns := []string{
        "127.0.0.1",
        "localhost",
        "169.254",
        "metadata",
        "\.internal",
    }
    for _, pattern := range patterns {
        if strings.Contains(input, pattern) {
            return true
        }
    }
    return false
}

Network-level SSRF mitigation using Go's HTTP client with custom transport:

type restrictedTransport struct {
    http.RoundTripper
}

func (t *restrictedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    host, _, err := net.SplitHostPort(req.URL.Host)
    if err != nil {
        host = req.URL.Host
    }
    
    if isPrivateIP(host) || isMetadataService(host) {
        return nil, errors.New("blocked host: private IP or metadata service")
    }
    
    return t.RoundTripper.RoundTrip(req)
}

func NewSafeHTTPClient() *http.Client {
    return &http.Client{
        Transport: &restrictedTransport{
            http.DefaultTransport,
        },
        Timeout: 10 * time.Second,
    }
}

Integrating SSRF protection into Chi applications using middleBrick's CI/CD integration ensures continuous monitoring:

- name: Run SSRF security scan
  run: |
    npx middlebrick scan http://staging.your-chi-app.com \
      --fail-below B \
      --output json > ssrf-report.json
    if [ $? -ne 0 ]; then
      echo "SSRF vulnerabilities detected!"
      exit 1
    fi

Frequently Asked Questions

How can I test if my Chi application has SSRF vulnerabilities?
Use middleBrick's self-service scanner by running npx middlebrick scan <your-chi-app-url>. The scanner tests for SSRF by attempting requests to private IP ranges, cloud metadata services, and other SSRF indicators. It also analyzes your OpenAPI spec if available and checks for SSRF patterns in your runtime behavior.
What's the difference between blind SSRF and regular SSRF in Chi applications?
Regular SSRF in Chi shows immediate responses (like proxying content back to the user), while blind SSRF makes requests that don't return data to the user but can still cause side effects. Blind SSRF is harder to detect but can be used for port scanning, internal service enumeration, or triggering actions in internal systems. middleBrick tests for both by checking response behaviors and attempting to trigger measurable side effects.