JuliusBrussee/caveman · error
ssrf: URL must contain a host
Error message
ssrf: URL must contain a host
What it means
ssrf.ValidateURL requires a non-empty host component (u.Hostname()). URLs like 'https:///path', 'https://?q=1', or scheme-only strings parse successfully but have no host, so the guard rejects them before DNS resolution.
Source
Thrown at shared/platform/ssrf/ssrf.go:174
//
// Errors are safe to return to callers; they contain the blocked IP but never
// the original credential material.
func ValidateURL(ctx context.Context, raw string, cfg Config) error {
u, err := url.Parse(raw)
if err != nil {
// net/url.Error includes the raw URL (and may therefore include
// credentials or query secrets). Keep this error field-only and stable.
return errors.New("ssrf: invalid URL")
}
if u.Scheme != "https" && !(u.Scheme == "http" && !cfg.ManagedMode) {
return fmt.Errorf("ssrf: scheme %q not permitted (managed mode requires https)", u.Scheme)
}
if u.User != nil {
return fmt.Errorf("ssrf: credentials embedded in URL are forbidden")
}
host := u.Hostname()
if host == "" {
return fmt.Errorf("ssrf: URL must contain a host")
}
port := u.Port()
if cfg.ManagedMode && port != "" && port != "443" {
return errors.New("ssrf: managed mode requires port 443")
}
if port == "" {
if u.Scheme == "https" {
port = "443"
} else {
port = "80"
}
}
return validateHostPort(ctx, host, port, cfg)
}
// ValidateHost resolves host (bare hostname or IP literal) and checks all
// resolved addresses. Use when you have a host/port pair rather than a full
// URL.View on GitHub (pinned to 27d5a3981a)
Solutions
- Check the host/env var is set before constructing the URL.
- Require a full absolute URL at the input layer (form field placeholder/validation) and reject relative paths.
- Default the host explicitly (e.g. api.example.com) instead of concatenating possibly-empty values.
Example fix
// before
u := "https://" + os.Getenv("PROVIDER_HOST") + "/v1" // host unset -> https:///v1
// after
host := os.Getenv("PROVIDER_HOST")
if host == "" { return errors.New("PROVIDER_HOST not set") }
u := "https://" + host + "/v1" Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(raw)
if err != nil || u.Hostname() == "" {
return fmt.Errorf("a complete absolute URL with host is required")
} Type guard
func hasHost(raw string) bool {
u, err := url.Parse(raw)
return err == nil && u.Hostname() != ""
} Prevention
- Require absolute URLs in webhook/endpoint fields and validate on save.
- Fail fast on empty host env vars before string-concatenating URLs.
When it happens
Trigger: Calling ssrf.ValidateURL with a URL whose authority is empty: 'https:///health', 'https:/health', relative paths like '/api/hook', or empty strings that still parse.
Common situations: Building URLs by string concatenation where the host variable is empty (unset env var); users entering only a path in a webhook field; a config default of '' slipping through.
Related errors
- ssrf: scheme %q not permitted (managed mode requires https)
- ssrf: credentials embedded in URL are forbidden
- {name} must not contain surrounding whitespace
- {name} must be an absolute http(s) URL
- {name} must be an absolute http(s) URL without credentials
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/ebb56e376edace00.
Report an issue: GitHub.