Dangling Dns in Echo Go with Bearer Tokens
Dangling Dns in Echo Go with Bearer Tokens — how this specific combination creates or exposes the vulnerability
A dangling DNS configuration in an Echo Go service becomes high risk when endpoints are protected only by Bearer tokens. In this combination, authentication is present (Bearer token header checks), but the underlying route or upstream resolver can be manipulated or unresolved, allowing an unauthenticated attacker to influence request routing or leak information through indirect references.
Echo Go does not inherently validate that a route target hostname resolves at request time. If a route uses a hostname derived from user input or configuration and that hostname later becomes unresolved or points to an unexpected host, the request may be forwarded to an unintended location. When combined with Bearer tokens, this can expose whether authentication logic is enforced upstream or whether token validation is delegated elsewhere. An attacker can probe endpoints with crafted hostnames to observe differences in behavior, timing, or error messages, which may reveal whether a token is accepted or rejected before a dangling resolution causes a failure.
For example, an API route defined as /api/v1/admin might forward to a backend hostname stored in configuration. If that hostname is not resolvable, Echo may return a network error, but under some conditions it might inadvertently forward requests without proper host validation. If an attacker can supply a hostname that resolves to a malicious server, they can observe whether the service sends the Bearer token in requests to that server, effectively testing the presence and handling of tokens. This becomes an information leak about the security boundary even when authentication appears enforced at the gateway.
In the context of middleBrick’s 12 checks, this scenario can surface findings in Property Authorization and Input Validation. Property Authorization ensures that authorization rules apply consistently to each route, and dangling DNS can bypass those rules if routing is inconsistent. Input Validation flags cases where hostnames or URLs are used without strict allowlists or resolution checks. An unauthenticated LLM endpoint probe (if present) could also test whether AI-related routes are similarly vulnerable when tokens are expected but resolution is broken.
Because middleBrick scans the unauthenticated attack surface, it can detect mismatches between declared authentication (Bearer token requirement) and actual routing behavior. A dangling DNS setup may cause inconsistent status codes, redirect chains, or error responses that expose whether token validation occurs before network resolution. This inconsistency can be flagged as a BOLA/IDOR or Property Authorization finding, depending on how the route definitions and token usage are implemented.
To illustrate a correct implementation in Echo Go, ensure hostnames are validated before use and that routes do not rely on dynamic resolution without safeguards. Use strict hostname allowlists and perform resolution early in the request lifecycle, returning 400 for unresolved targets rather than allowing the request to proceed.
Bearer Tokens-Specific Remediation in Echo Go — concrete code fixes
Remediation focuses on validating hostnames before making outbound calls and ensuring Bearer token handling is consistent and never delegated to unresolved endpoints. Below are concrete examples showing insecure patterns and their secure counterparts.
Insecure pattern: dynamic hostname with Bearer forwarding
package main
import (
"net/http"
"net/url"
"github.com/labstack/echo/v4"
)
func unsafeHandler(c echo.Context) error {
targetHost := c.QueryParam("host") // user-controlled
u := &url.URL{
Scheme: "https",
Host: targetHost,
Path: "/admin",
}
req, _ := http.NewRequest(http.MethodGet, u.String(), nil)
req.Header.Set("Authorization", "Bearer "+c.Get("token").(string))
// No hostname validation; token may be sent to arbitrary host
resp, err := http.DefaultClient.Do(req)
if err != nil {
return c.String(http.StatusInternalServerError, "upstream error")
}
defer resp.Body.Close()
return c.Status(resp.StatusCode).Send()
}
This pattern is risky because targetHost is uncontrolled, and the Bearer token is sent to whatever host resolves, which may be unintended or malicious.
Secure pattern: strict hostname allowlist and early validation
package main
import (
"errors"
"net/http"
"net/url"
"strings"
"github.com/labstack/echo/v4"
)
var allowedHosts = map[string]bool{
"api.example.com": true,
"internal.example.com": true,
}
func validateHostname(h string) error {
if h == "" {
return errors.New("missing host")
}
if !allowedHosts[h] {
return errors.New("host not allowed")
}
// Optionally verify DNS resolution here before use
return nil
}
func secureHandler(c echo.Context) error {
targetHost := c.QueryParam("host")
if err := validateHostname(targetHost); err != nil {
return c.String(http.StatusBadRequest, "invalid host")
}
u := &url.URL{
Scheme: "https",
Host: targetHost,
Path: "/admin",
}
req, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return c.String(http.StatusBadRequest, "invalid request")
}
req.Header.Set("Authorization", "Bearer "+c.Get("token").(string))
// Only send token to validated host
resp, err := http.DefaultClient.Do(req)
if err != nil {
return c.String(http.StatusInternalServerError, "upstream error")
}
defer resp.Body.Close()
return c.Status(resp.StatusCode).Send()
}
In the secure version, validateHostname enforces an allowlist, preventing requests to dangling or unexpected hosts. The Bearer token is only attached after hostname validation, reducing the risk of leaking credentials to unintended endpoints.
Additionally, ensure that token retrieval fails safely if missing or malformed, and avoid logging full Authorization headers. These practices align with Property Authorization checks and Input Validation expectations that middleBrick assesses.