---
id: "GHSA-r766-rf9f-588h"
page: "https://infrastack.ai/live/GHSA-r766-rf9f-588h"
kind: "vulnerability"
aliases: ["GHSA-r766-rf9f-588h"]
title: "Host and :authority values with dot segments or slashes escape a {host}-based root"
severity: "high"
cvss: null
epss: null
exploited: false
status: "open"
category: "package"
products: [{"name": "github.com/caddyserver/caddy/v2", "fixed": ["2.11.8"], "affected": "<= 2.11.7", "ecosystem": "go"}]
ecosystems: ["go"]
tags: ["caddy", "cwe-22", "frankenphp", "go", "package", "php", "self-hosted"]
not_affected_if: ["explicit-host-names", "managed-hosting", "static-root"]
published_at: "2026-11-04T00:59:13+00:00"
first_seen_at: "2026-11-09T22:53:33+00:00"
updated_at: "2026-11-09T22:58:47+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/caddyserver/caddy/security/advisories/GHSA-r766-rf9f-588h", "first_seen_at": "2026-11-09T22:53:33+00:00"}]
exploit_sources: []
---

# Host and :authority values with dot segments or slashes escape a {host}-based root

Link for people: https://infrastack.ai/live/GHSA-r766-rf9f-588h (this .md is for agents)

A Caddy site whose root uses the request host lets a client pick the document root with a crafted Host or :authority value, such as '..' or '../../etc'. An unauthenticated attacker can then read any file the Caddy process can read and, with php_fastcgi or FrankenPHP, run any .php file on the filesystem.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- go:github.com/caddyserver/caddy/v2 affected <= 2.11.7 fixed 2.11.8

## How to check

- Search your Caddyfile for `root` directives that contain `{host}` or another request-derived placeholder.
- Check the Caddy version with `caddy version`; affected builds are `2.11.7` and earlier.
- Sites that list their host names explicitly are not affected, per the advisory.

## Fix

- Upgrade github.com/caddyserver/caddy/v2 to `2.11.8`.

## Timeline

- 2026-11-09T22:53:33+00:00 ghsa-repo https://github.com/caddyserver/caddy/security/advisories/GHSA-r766-rf9f-588h

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/caddyserver/caddy/security/advisories/GHSA-r766-rf9f-588h

## From the sources

### Summary

A site whose root uses the request host (`root /srv/sites/{host}`) lets the client choose the document root. HTTP/1.1 accepts `Host: ..`, and the HTTP/2 and HTTP/3 servers accept `/` and `\` in `:authority`, so `../../etc` moves the root anywhere on the filesystem. `file_server` serves files and `php_fastcgi` runs `.php` files outside the intended tree.

### Details

What reaches Caddy, per protocol (Go 1.27, quic-go v0.63.0):

| Host value | HTTP/1.1 (`Host` or absolute-form) | HTTP/2 `:authority` | HTTP/3 `:authority` |
|---|---|---|---|
| `.`, `..`, `...` | accepted | accepted | accepted |
| contains `/`, `\` or a space | 400 | accepted | accepted |
| contains NUL | 400 | stream error | stream error |

`httpguts.ValidHostHeader` covers only HTTP/1. The HTTP/2 and HTTP/3 servers check `:authority` with `ValidHeaderFieldValue` alone, which rejects control bytes but allows `/`, `\` and spaces. The expanded root then goes through `FastAbs`, which cleans the dot segments instead of rejecting them. On Windows, `FastAbs` calls `GetFullPathNameW`, which also trims trailing dots and spaces from the last segment, so `...` can resolve like `.` and `.. ` like `..`.

Fix: `Server.serveHTTP` applies `httpguts.ValidHostHeader` to every protocol, and responds 400 when the host, port stripped, is made only of dots. Hosts such as `example.com.` keep working. Patch: public PR from `dunglas:caddyhttp-reject-path-like-host`.

Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-YKIEF8GR.

### Proof of concept

```caddyfile
{
	servers {
		protocols h1 h2c
	}
}

:8080 {
	root /srv/sites/{host}
	file_server
}
```

```console
# HTTP/1.1: the root becomes /srv, serving /srv/secret.txt
curl -H 'Host: ..' http://localhost:8080/secret.txt

# HTTP/2: curl sends the Host value as :authority; the root becomes /etc
curl --http2-prior-knowledge -H 'Host: ../../etc' http://localhost:8080/passwd
```

Both return 200 on master. The same works over TLS with HTTP/2 and HTTP/3.

### Impact

On catch-all or on-demand TLS sites with a host-derived root, unauthenticated clients read any file the Caddy process can read and, with `php_fastcgi` or FrankenPHP, run any `.php` file on the filesystem. Sites that list their host names are not affected.

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
