VYPR
High severityNVD Advisory· Published Feb 24, 2026· Updated Feb 27, 2026

Caddy: MatchHost becomes case-sensitive for large host lists (>100), enabling host-based route/auth bypass

CVE-2026-27588

Description

Caddy is an extensible server platform that uses TLS by default. Prior to version 2.11.1, Caddy's HTTP host request matcher is documented as case-insensitive, but when configured with a large host list (>100 entries) it becomes case-sensitive due to an optimized matching path. An attacker can bypass host-based routing and any access controls attached to that route by changing the casing of the Host header. Version 2.11.1 contains a fix for the issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/caddyserver/caddy/v2Go
< 2.11.12.11.1

Affected products

1

Patches

1
eec32a0bb5a1

Merge commit from fork

https://github.com/caddyserver/caddyAsim Viladi Oglu ManizadaFeb 20, 2026via ghsa
1 file changed · +10 5
  • modules/caddyhttp/matchers.go+10 5 modified
    @@ -262,13 +262,17 @@ func (m MatchHost) Provision(_ caddy.Context) error {
     		if err != nil {
     			return fmt.Errorf("converting hostname '%s' to ASCII: %v", host, err)
     		}
    -		if asciiHost != host {
    -			m[i] = asciiHost
    -		}
     		normalizedHost := strings.ToLower(asciiHost)
     		if firstI, ok := seen[normalizedHost]; ok {
     			return fmt.Errorf("host at index %d is repeated at index %d: %s", firstI, i, host)
     		}
    +		// Normalize exact hosts for standardized comparison in large-list fastpath later on.
    +		// Keep wildcards/placeholders untouched.
    +		if m.fuzzy(asciiHost) {
    +			m[i] = asciiHost
    +		} else {
    +			m[i] = normalizedHost
    +		}
     		seen[normalizedHost] = i
     	}
     
    @@ -312,14 +316,15 @@ func (m MatchHost) MatchWithError(r *http.Request) (bool, error) {
     	}
     
     	if m.large() {
    +		reqHostLower := strings.ToLower(reqHost)
     		// fast path: locate exact match using binary search (about 100-1000x faster for large lists)
     		pos := sort.Search(len(m), func(i int) bool {
     			if m.fuzzy(m[i]) {
     				return false
     			}
    -			return m[i] >= reqHost
    +			return m[i] >= reqHostLower
     		})
    -		if pos < len(m) && strings.EqualFold(m[pos], reqHost) {
    +		if pos < len(m) && m[pos] == reqHostLower {
     			return true, nil
     		}
     	}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.