Heimdall: Forwarded Header Injection via Unsanitized Host Header in Proxy ModeGHSA-4jgr-pg2m-m988
GHSA-4jgr-pg2m-m988 is a Improper Input Validation vulnerability in github.com/dadrus/heimdall. A fix is available for github.com/dadrus/heimdall — see the affected versions and patch details below.
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
Exploitation and automatability from CISA’s SSVC triage for GHSA-4jgr-pg2m-m988.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
github.com/dadrus/heimdallReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
When Heimdall operates in proxy mode, it constructs the Forwarded HTTP header after executing the matched rule pipeline by inserting the incoming request's Host header value directly into the header string without sanitizing commas or semicolons. This allows an attacker to inject additional parameters into the Forwarded header, potentially spoofing IP addresses for upstream services.
Vulnerable Code
File: proxy/request_context.go (line 201)
entry := "for=" + clientIP + ";host=" + in.Host + ";proto=" + proto
Go's net/http allows commas and semicolons in Host header values. No sanitization is applied before string concatenation.
PoC
# Inject a spoofed IP into the Forwarded header
curl -s -H "Host: evil.com,for=127.0.0.1" \
"http://TARGET:PORT/protected-resource"
This produces the following Forwarded header sent to the upstream service:
Forwarded: for=1.2.3.4;host=evil.com, for=127.0.0.1;proto=http
Upstream services that parse the Forwarded header according to RFC 7239 will see two entries. If the service trusts the last or any for= value, the attacker successfully spoofs 127.0.0.1 as the client IP.
# More targeted attack: spoof to bypass IP allowlist
curl -s -H "Host: legit.com;for=10.0.0.1;proto=https,for=192.168.1.1" \
"http://TARGET:PORT/admin-panel"
Impact
- IP spoofing: Upstream services behind Heimdall may trust the injected
for=value, believing the request originates from an internal/trusted IP - Access control bypass: Applications that restrict access based on IP address by themselves, without using the corresponding heimdall capabilities (e.g., admin panels, internal APIs), can be bypassed
- Affects all proxy-mode deployments where upstream services parse the
Forwardedheader.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/dadrus/heimdall | all versions | 0.17.17go get github.com/dadrus/heimdall@v0.17.17 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/dadrus/heimdall, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update github.com/dadrus/heimdall to 0.17.17 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-4jgr-pg2m-m988 is resolved across your whole dependency graph.
Workarounds
Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.
Frequently Asked Questions
Is GHSA-4jgr-pg2m-m988 in your dependencies?
Find it across Go, including transitive dependencies.