GHSA-pj7v-xfvx-wmjq

Suggest an improvement
Source
https://github.com/advisories/GHSA-pj7v-xfvx-wmjq
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-pj7v-xfvx-wmjq/GHSA-pj7v-xfvx-wmjq.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-pj7v-xfvx-wmjq
Aliases
Published
2026-06-26T21:54:55Z
Modified
2026-06-26T22:00:10Z
Severity
  • 6.9 (Medium) CVSS_V4 - CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N CVSS Calculator
Summary
Hackney has SSRF allowlist bypass in hackney_url:normalize/2 via percent-encoded host
Details

Summary

hackney_url:normalize/2 URL-decodes the host component of a parsed URL, but the caller's SSRF allowlist runs before normalization using OTP's uri_string:parse/1 and inet:parse_address/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/hackney_url.erl (lines 161–186), normalize/2 checks whether the parsed host is already a dotted-quad or IPv6 literal via inet_parse: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:

Host1 = binary_to_list(
           urldecode(unicode:characters_to_binary(Host0))
         ),

The decoded host ("127.0.0.1") replaces the original in the returned #hackney_url{} record. hackney:request/5 at src/hackney.erl:463 always calls normalize/2, so the decoded host is what do_dispatch/1 and add_host_header/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 parse_url/1 and did not touch normalize/2.

PoC

  1. Validate the URL with the canonical Erlang SSRF allowlist: uri_string:parse/1 returns host <<"%31%32%37%2E%30%2E%30%2E%31">>, inet:parse_address/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

Database specific
{
    "cwe_ids":  [
        "CWE-436",
        "CWE-918"
    ],
    "github_reviewed":  true,
    "github_reviewed_at":  "2026-06-26T21:54:55Z",
    "nvd_published_at":  "2026-05-25T15:16:22Z",
    "severity":  "MODERATE"
}
References

Affected packages

Hex / hackney

Package

Name
hackney
Purl
pkg:hex/hackney

Affected ranges

Type
SEMVER
Events
Introduced
0.13.0
Fixed
4.0.1

Affected versions

0.*
0.13.1
0.14.0
0.14.1
0.14.2
0.14.3
0.15.0
0.15.2
1.*
1.0.1
1.0.2
1.0.5
1.0.6
1.1.0
1.2.0
1.3.0
1.3.1
1.3.2
1.4.0
1.4.1
1.4.2
1.4.3
1.4.4
1.4.5
1.4.6
1.4.7
1.4.8
1.4.10
1.5.0
1.5.1
1.5.2
1.5.3
1.5.4
1.5.5
1.5.6
1.5.7
1.6.0
1.6.1
1.6.2
1.6.3
1.6.4
1.6.5
1.6.6
1.7.0
1.7.1
1.8.0
1.8.2
1.8.3
1.8.4
1.8.5
1.8.6
1.9.0
1.10.0
1.10.1
1.11.0
1.12.0
1.12.1
1.13.0
1.14.0
1.14.2
1.14.3
1.15.0
1.15.1
1.15.2
1.16.0
1.17.0
1.17.1
1.17.2
1.17.3
1.17.4
1.18.0
1.18.1
1.18.2
1.19.0
1.19.1
1.20.0
1.20.1
1.21.0
1.22.0
1.23.0
1.24.0
1.24.1
1.25.0
2.*
2.0.0-beta.1
2.0.0
2.0.1
3.*
3.0.0
3.0.1
3.0.2
3.0.3
3.1.0
3.1.1
3.1.2
3.2.0
3.2.1
4.*
4.0.0

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/06/GHSA-pj7v-xfvx-wmjq/GHSA-pj7v-xfvx-wmjq.json"