CVE-2026-47076: SSRF allowlist bypass via percent-encoded host in hackney

Published May 25, 2026
·
Updated

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

3 affected componentsFixes available
hex/hackney>=0.13.0<4.0.1
benoitc hackney>=0.13.0<4.0.1
erlang/hackney>=0.13.0<4.0.1
4.0.1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade erlang/hackney to a version that resolves this vulnerability.

    Fixed in 4.0.1

Event History

May 25, 2026
CVE Published
via MITRE·02:00 PM
Data Sourced
via MITRE·02:00 PM
DescriptionWeakness
Data Sourced
via NVD·03:16 PM
RemedyDescriptionSeverityWeaknessAffected Software
Jun 26, 2026
Advisory Published
via GitHub·09:54 PM
Data Sourced
via GitHub·09:54 PM
DescriptionWeaknessAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2026-47076?

CVE-2026-47076 has a risk rating of 70, indicating a medium severity level.

2

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.

3

What software is affected by CVE-2026-47076?

CVE-2026-47076 affects the hex/hackney library.

4

What type of vulnerability is CVE-2026-47076?

CVE-2026-47076 is classified as a Server Side Request Forgery (SSRF) vulnerability.

5

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.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203