HIGH ssrf server sideecho gobasic auth

Ssrf Server Side in Echo Go with Basic Auth

Ssrf Server Side in Echo Go with Basic Auth — how this specific combination creates or exposes the vulnerability

Server-Side Request Forgery (SSRF) in an Echo Go service that uses HTTP Basic Authentication can occur when user-supplied URLs are passed to backend HTTP clients without validation. In this setup, the service typically accepts a URL from a client, adds Basic Auth credentials (username and password), and forwards the request. If the user can control the target hostname, path, or even the port, they may direct the server to internal endpoints that are not exposed publicly. Examples include metadata services at http://169.254.169.254 (AWS instance metadata), Kubernetes services via http://kubernetes.default.svc, or internal dashboards on loopback addresses like http://127.0.0.1:8080/health. Because the server adds Basic Auth headers, the backend may trust the request more than an unauthenticated one, increasing the impact of SSRF by enabling access to otherwise protected internal resources.

Echo Go does not inherently introduce SSRF; the risk arises from how routes and handlers are implemented. A typical vulnerable pattern is using echo.Context.Query to obtain a target URL and then creating an http.Request with http.NewRequest, setting headers that include Basic Auth derived from environment variables or configuration. If the hostname is not restricted, an attacker can supply a URL that causes the server to perform SSRF against internal services. Even when Basic Auth is used, SSRF remains critical because the server may act as a proxy to internal systems that rely on IP-based allowlists or trust relationships, bypassing perimeter defenses.

OpenAPI/Swagger spec analysis can highlight such risks when external or user-supplied parameters are mapped directly to request construction logic. For instance, a path parameter defined as {url: string} without strict format validation can lead to SSRF when combined with outgoing HTTP calls. The scanner’s checks for SSRF, when run against an OpenAPI 2.0 or 3.0 spec with full $ref resolution, can detect endpoints where user input influences outbound destinations and flag them regardless of whether Basic Auth is present. This is important because Basic Auth alone does not mitigate SSRF; it only provides credentials for the outbound request, which may be forwarded to unintended internal endpoints.

Real-world attack patterns mirror this scenario. An attacker might send a request such as GET /proxy?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/ to an Echo Go service that adds Basic Auth headers and forwards the request. The server, acting on the attacker’s behalf, retrieves sensitive metadata. Similarly, probing internal services on 127.0.0.1 or internal Kubernetes DNS names can reveal development endpoints, version information, or misconfigured services. These examples highlight that Basic Auth in the forwarding path does not reduce the likelihood of SSRF and can inadvertently increase the value of SSRF findings to an attacker.

Basic Auth-Specific Remediation in Echo Go — concrete code fixes

To remediate SSRF in Echo Go when using Basic Auth, you must avoid forwarding user-supplied URLs directly and, if forwarding is necessary, enforce strict allowlisting and validation. Do not rely on Basic Auth to prevent SSRF; treat user input as untrusted even when credentials are added by the server. Below are concrete, secure coding patterns.

Example 1: Reject non-allowed hosts

Define an allowlist of permitted hosts and reject any URL whose host is not on that list. This prevents redirection to internal services regardless of the presence of Basic Auth headers.

import (
    "net/http"
    "net/url"
    "strings"

    "github.com/labstack/echo/v4"
)

var allowedHosts = map[string]bool{
    "api.example.com": true,
    "data.example.com": true,
}

func safeProxy(c echo.Context) error {
    target := c.QueryParam("url")
    if target == "" {
        return echo.NewHTTPError(http.StatusBadRequest, "url query parameter is required")
    }
    u, err := url.Parse(target)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid url")
    }
    if !allowedHosts[u.Host] {
        return echo.NewHTTPError(http.StatusForbidden, "host not allowed")
    }

    req, err := http.NewRequest(c.Request().Method, u.String(), nil)
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "failed to create request")
    }

    // Add Basic Auth only for allowed hosts
    req.SetBasicAuth("username", "password")

    // Use a configured HTTP client with timeouts
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadGateway, "failed to reach target")
    }
    defer resp.Body.Close()

    // Forward response status and selected headers as needed
    c.Response().WriteHeader(resp.StatusCode)
    return nil
}

Example 2: Use a request wrapper to scrub sensitive headers and enforce timeouts

When forwarding is required, ensure you do not leak credentials or headers that could be abused. Use a custom transport or client with timeouts and avoid copying user-supplied headers blindly.

import (
    "context"
    "net/http"
    "time"

    "github.com/labstack/echo/v4"
)

func proxyWithTimeout(c echo.Context) error {
    target := c.QueryParam("url")
    u, err := url.Parse(target)
    if err != nil || !strings.HasPrefix(u.Host, "allowed.example.com") {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid or disallowed target")
    }

    ctx, cancel := context.WithTimeout(c.Request().Context(), 10*time.Second)
    defer cancel()

    req, err := http.NewRequestWithContext(ctx, c.Request().Method, u.String(), nil)
    if err != nil {
        return echo.NewHTTPError(http.StatusInternalServerError, "request error")
    }

    // Set credentials explicitly; do not forward user headers
    req.SetBasicAuth("svc_user", "svc_password")

    client := &http.Client{
        Timeout: 15 * time.Second,
    }
    resp, err := client.Do(req)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadGateway, "upstream error")
    }
    defer resp.Body.Close()

    c.Response().WriteHeader(resp.StatusCode)
    return nil
}

These patterns ensure that SSRF is mitigated by controlling destinations and not by relying on authentication. The scanner’s checks for unsafe consumption and SSRF, when run against your OpenAPI spec, can validate that user input does not dictate outbound endpoints. middleBrick’s scan can be integrated into your workflow using the CLI (middlebrick scan <url>) or the GitHub Action to fail builds if risky patterns are detected, and findings map to frameworks such as OWASP API Top 10 to guide remediation.

Frequently Asked Questions

Does using Basic Auth in Echo Go prevent SSRF?
No. Basic Auth provides credentials for outbound requests but does not restrict where those requests can go. SSRF mitigation requires validating and restricting target hosts, independent of authentication.
How can I test my Echo Go endpoints for SSRF and Basic Auth handling?
Use middleBrick’s scanner via the CLI (middlebrick scan <url>) or the GitHub Action to automatically check for SSRF and other API risks. The tool reports findings with severity and remediation guidance, helping you validate controls without manual penetration testing.