HIGH ssrfecho gobasic auth

Ssrf in Echo Go with Basic Auth

Ssrf 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 an HTTP client without validation and the client includes Basic Auth credentials. In this configuration, an attacker can coerce the server into making authenticated requests to internal or external endpoints, potentially reaching metadata services or bypassing network segregation. Because the server holds the Basic Auth credentials (username and password or a token derived from them), any outbound request it performs on behalf of an attacker can carry those credentials, even to internal addresses that are normally protected by network-level access controls.

Echo Go handlers often accept a URL query parameter to define a target resource. If that parameter is forwarded to an HTTP client such as net/http or a wrapper like resty, and the client attaches Basic Auth headers taken from environment variables or configuration, the server may unintentionally make authenticated requests to arbitrary destinations. Internal services that expose administrative endpoints over HTTP (rather than mutual TLS or strict IP whitelisting) can be enumerated or abused. In addition, cloud metadata endpoints (for example, 169.254.169.254 on many platforms) may accept unauthenticated or default-authenticated requests; if Basic Auth credentials are forwarded there, the server may still perform the request, and any error handling might leak information about internal network layout or credentials in logs or response bodies.

SSRF in this context is not solely about whether the target is internal or external; it is about the intersection of user-controlled redirection and server-side authentication material. Because the Basic Auth credentials travel with every request made by the client, an attacker can probe internal endpoints that would otherwise require network access, effectively pivoting through the compromised service. The attack surface expands further if the Echo server also follows redirects automatically, allowing the attacker to chain internal hops or force authentication headers to be sent to unexpected origins. Logging of request URLs and headers may inadvertently expose paths or credentials, so input validation and header management are essential to reduce both detection and abuse risks.

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

Remediation focuses on preventing user-controlled influence over the request destination and avoiding automatic inclusion of server-side credentials. Do not forward user-supplied URLs directly to an HTTP client that attaches stored Basic Auth headers. Instead, use allowlists for destinations, disable automatic redirect following, and avoid attaching credentials when they are not strictly required. When authenticated outbound calls are necessary, use explicit, scoped credentials tied to the target service rather than global Basic Auth pulled from configuration.

Below are concrete, secure patterns in Echo Go. The insecure example demonstrates the vulnerability; the secure example shows a hardened approach.

// Insecure example — do not use
package main

import (
	"net/http"
	"github.com/labstack/echo/v4"
)

func unsafeProxy(c echo.Context) error {
	url := c.QueryParam("url")
	req, _ := http.NewRequest(http.MethodGet, url, nil)
	req.SetBasicAuth("admin", "secret")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return c.JSONBlob(resp.StatusCode, nil)
}

In this vulnerable code, url is taken directly from the query string and used by http.NewRequest. The Basic Auth credentials are attached to every request, including those to internal or malicious destinations. Automatic redirects will forward credentials, and there is no restriction on hosts or schemes.

// Secure example — allowlisted destinations and no auto auth
package main

import (
	"errors"
	"net/http"
	"net/url"
	"strings"
	"github.com/labstack/echo/v4"
)

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

func safeProxy(c echo.Context) error {
	raw := c.QueryParam("url")
	parsed, err := url.ParseRequestURI(raw)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, "invalid url")
	}
	if !allowedHosts[parsed.Host] {
		return echo.NewHTTPError(http.StatusForbidden, "host not allowed")
	}
	// Ensure only HTTP/HTTPS to prevent unexpected schemes
	if parsed.Scheme != "http" && parsed.Scheme != "https" {
		return echo.NewHTTPError(http.StatusBadRequest, "invalid scheme")
	}
	// Build request without inheriting global auth; auth is set only when explicitly required for the allowlisted target
	req, err := http.NewRequest(http.MethodGet, parsed.String(), nil)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, "failed to build request")
	}
	// Avoid SetBasicAuth unless the target specifically requires it and the credential scope is tightly controlled
	// req.SetBasicAuth("admin", "secret")
	client := &http.Client{
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastRedirect
		},
	}
	resp, err := client.Do(req)
	if err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, "request failed")
	}
	defer resp.Body.Close()
	return c.JSONBlob(resp.StatusCode, nil)
}

In the secure version, the destination host is validated against an explicit allowlist, the scheme is restricted, redirects are rejected to prevent chaining, and Basic Auth is not automatically attached. If authentication is required for an allowed endpoint, it should be configured per-target using scoped tokens or alternative mechanisms rather than global Basic Auth credentials.

Additional hardening steps include disabling automatic credential propagation, sanitizing logs to avoid leaking paths or headers, and monitoring for unusual outbound host patterns. These measures reduce the likelihood that an SSRF vector can leverage Basic Auth material to reach sensitive internal services or cloud metadata endpoints.

Related CWEs: ssrf

CWE IDNameSeverity
CWE-918Server-Side Request Forgery (SSRF) CRITICAL
CWE-441Unintended Proxy or Intermediary (Confused Deputy) HIGH

Frequently Asked Questions

Can SSRF occur if Basic Auth credentials are stored only in environment variables and not in code?
Yes. If your Echo Go handler forwards user-controlled URLs to an HTTP client and attaches those environment-derived credentials, SSRF remains possible because the server will send those credentials to arbitrary destinations.
Is it acceptable to allowlist by domain alone, or should I include the full origin including scheme and port?
Include scheme, host, and port (e.g., https://api.example.com:443). Domain-only allowlists can permit attackers to abuse different schemes or ports to reach unexpected services.