Custom cacerts or cacertfile do not restrict trust to the pinned CA in hackney
## Summary Improper Certificate Validation vulnerability in `hackney_ssl` in benoitc hackney allows an on-path attacker to impersonate a server pinned to a private certificate authority via a certificate chain that ends in a publicly trusted root. hackney adds `{partial_chain, fun hackney_ssl:partial_chain/1}` to every `verify_peer` configuration. The callback returns any certificate in the peer chain whose public key matches a root in the bundled certifi store as the trust anchor, and OTP honours that callback over the configured `cacerts`. `hackney_ssl:merge_ssl_opts/3` kept the callback when the caller replaced the trust store with `cacerts` or `cacertfile` in `ssl_options`, so a connection pinned to a private CA still accepted any chain that carried a publicly trusted root. The hostname check still applies, so the attacker needs a publicly trusted certificate for the pinned hostname. This issue affects hackney: from 1.24.0 before 4.9.0. ## Details **1. Default trust options.** `hackney_ssl:check_hostname_opts/1` builds the `verify_peer` options for every TLS connection: the certifi `cacerts`, a hostname `verify_fun`, and `{partial_chain, fun hackney_ssl:partial_chain/1}`. The callback walks the peer chain and returns `{trusted_ca, Cert}` for the first certificate whose public key matches a root in the bundled certifi store, which lets OTP accept chains that end in a cross-signed root. **2. Merge keeps the callback.** When the caller passes `ssl_options`, `hackney_ssl:merge_ssl_opts/3` merges them over the defaults with the caller's values winning per key. `cacerts` or `cacertfile` replace the trust store, and a `cacertfile` removes the default `cacerts`, but `partial_chain` has no counterpart in the caller's options and stays. **3. Validation.** OTP consults `partial_chain` before the configured trust store. A peer chain that carries any publicly trusted root therefore gets that root as its trust anchor, and the pinned `cacerts` are never consulted. Only the hostname `verify_fun` still constrains the attacker. ## Impact An attacker positioned between the client and a server pinned to a private CA, holding a publicly trusted certificate for the pinned hostname, can impersonate the server and read or modify the traffic the client sends and receives. ## Workarounds Pass your own `{partial_chain, Fun}` in `ssl_options` alongside `cacerts` or `cacertfile`. A caller-supplied `partial_chain` replaces hackney's in the merge, and a callback that returns `unknown_ca` makes OTP validate against the configured `cacerts` only. ## Configurations The caller passes `cacerts` or `cacertfile` in `ssl_options` to restrict trust to a private CA, without a `partial_chain` of its own. Connections that use hackney's default certifi trust store are not affected.
describes (1)
Related CVEs.
| ID | severity | exploitable | ||
|---|---|---|---|---|
| CVE-2026-115693US | — | — | ||
Improper Certificate Validation vulnerability in hackney_ssl in benoitc hackney allows an on-path attacker to impersonate a server pinned to a private certificate authority via a c… | ||||
references
External citations — patches, advisories, analysis.
- https://cna.erlef.org/cves/CVE-2026-115693.htmlWEB
- https://github.com/benoitc/hackney/commit/915eb5737e9c489d8fc22eec8cdae30e9b027be4FIX
- https://github.com/benoitc/hackney/commit/d8a9afcf5c3849904274e2eba1df56c63d1a1a0cWEB
- https://github.com/benoitc/hackney/pull/978WEB
- https://github.com/benoitc/hackney/releases/tag/4.9.0ADVISORY
- https://hex.pm/packages/hackneyPACKAGE
Advisories like this name the exposed products attackers go after on your perimeter. See what is exposed on your perimeter with a free passive scan.
Free scan