CVE-2026-47076: SSRF allowlist bypass via percent-encoded host in hackney
Summary
hackneyurl:normalize/2 URL-decodes the host component of a parsed URL, but the caller's SSRF allowlist runs before normalization using OTP's uristring:parse/1 and inet:parseaddress/1, neither of which decodes percent-escapes in hostnames. A URL like http://%31%32%37%2E%30%2E%30%2E%31/ presents an encoded, non-IP-looking host to the validator, which passes the allowlist check; hackney's normalizer then decodes it to 127.0.0.1 and connects to loopback. Because hackney:request/5 always calls normalize/2 with no opt-out, every request path that accepts a binary or list URL is affected. This is a parser-differential SSRF in the same class as CVE-2025-1211, but in a different function.
Details
In src/hackneyurl.erl (lines 161–186), normalize/2 checks whether the parsed host is already a dotted-quad or IPv6 literal via inetparse:address/1. Percent-encoded forms like %31%32%37%2E%30%2E%30%2E%31 fail that check and fall into the catch-all branch, where urldecode/1 decodes the host before passing it to IDNA conversion:
erlang Host1 = binarytolist( urldecode(unicode:characterstobinary(Host0)) ),
The decoded host ("127.0.0.1") replaces the original in the returned #hackneyurl{} record. hackney:request/5 at src/hackney.erl:463 always calls normalize/2, so the decoded host is what dodispatch/1 and addhostheader/2 ultimately use. The on-wire Host: header and the TCP connect target both reflect the decoded value.
The same payload pattern reaches the AWS/GCP/Azure IMDS (169.254.169.254), RFC1918 ranges, and any localhost admin endpoint. The 1.21.0 patch for CVE-2025-1211 fixed a separate differential in parseurl/1 and did not touch normalize/2.
PoC
1. Validate the URL with the canonical Erlang SSRF allowlist: uristring:parse/1 returns host <<"%31%32%37%2E%30%2E%30%2E%31">>, inet:parseaddress/1 returns {error, einval}, so the allowlist accepts it. 2. Pass the same URL to hackney:get/1. 3. hackney's normalize/2 decodes the host to "127.0.0.1" and connects to 127.0.0.1:80. The internal service receives the request with Host: 127.0.0.1.
Impact
Unauthenticated SSRF bypassing the canonical Erlang allowlist pattern. Affects hackney 0.13.0 through 4.0.0 for any application that accepts attacker-supplied URLs. Targets include cloud IMDS endpoints, localhost admin interfaces, and RFC1918 backends. CVSS v4.0: 6.9 (MEDIUM).
Resources
Introduction commit: https://github.com/benoitc/hackney/commit/4d725507588942fd00efca15b86da3273656510a Patch commit: https://github.com/benoitc/hackney/commit/452620a92ec1da2e6b4862a049a2a4f04b42068f
Other sources
Interpretation Conflict vulnerability in benoitc hackney allows Server Side Request Forgery. hackneyurl:normalize/2 URL-decodes the host component after the URL has been parsed into a #hackneyurl{} record. OTP's uristring:parse/1 and inet:parseaddress/1 do not decode percent-escapes in the host, so a URL such as http://%31%32%37%2E%30%2E%30%2E%31/ is seen by a caller's allowlist validator with host %31%32%37%2E%30%2E%30%2E%31 (not an IP address), which passes the allowlist check. hackney's normalizer then decodes the host to 127.0.0.1 and opens a TCP connection to loopback. Because hackney:request/5 always calls hackneyurl:normalize/2 with no opt-out, every request that takes a binary or list URL is affected. The same technique reaches cloud instance metadata services (169.254.169.254), RFC1918 networks, and any admin interface listening on localhost.
This issue affects hackney: from 0.13.0 before 4.0.1.
— NVD
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
erlang/hackneyto a version that resolves this vulnerability.Fixed in 4.0.1
Event History
Frequently Asked Questions
What is the severity of CVE-2026-47076?
CVE-2026-47076 has a risk rating of 70, indicating a medium severity level.
How do I fix CVE-2026-47076?
To mitigate CVE-2026-47076, ensure that proper validation and sanitization of user input are implemented to prevent SSRF risks.
What software is affected by CVE-2026-47076?
CVE-2026-47076 affects the hex/hackney library.
What type of vulnerability is CVE-2026-47076?
CVE-2026-47076 is classified as a Server Side Request Forgery (SSRF) vulnerability.
What causes the CVE-2026-47076 vulnerability?
CVE-2026-47076 is caused by an interpretation conflict that allows for an allowlist bypass via percent-encoded hosts.