eef-cve-2026-89186
CVSS 6.3 osv_hex## Summary Use of Cache Containing Sensitive Information in ZenHive mpp allows a shared HTTP cache to store a paid response and serve it to clients that never paid. `MPP.Plug.verify_credential` in `lib/mpp/plug.ex` sets `payment-receipt` and `cache-control: private` on the connection before the wrapped application runs, and registers no `register_before_send/2` callback. `Plug.Conn.put_resp_header/3` replaces an existing header, so a mounting application that sets its own `cache-control` on the paid resource (for example `public, max-age=3600`) silently overrides the `private` the library relies on, and a CDN or reverse proxy can then store the paid 200 together with its `Payment-Receipt` and serve both to unpaid clients. The library-level guarantee is therefore defeatable by the application it protects. For the same reason a downstream non-2xx response still carried `Payment-Receipt`, issuing a receipt for a response that delivered no resource. This issue affects mpp: from 0.1.0 before 0.16.2. ## Impact An unpaid client requesting the same URL through the shared cache receives the cached paid response, including the `Payment-Receipt` header issued to the paying client. Operators lose the revenue for every cache hit, and the receipt identifying a paid transaction is disclosed to third parties. ## Workarounds In the application mounted behind `MPP.Plug`, stop setting `Cache-Control` on paid routes so the library's `private` survives to the response, or set a directive that is itself safe for a shared cache (`private`, or `no-store`). Where the application must set its own caching policy, configure the CDN or reverse proxy not to cache responses carrying a `Payment-Receipt` header. ## Configurations Reachable only where the application mounted behind `MPP.Plug` sets its own `Cache-Control` on the paid resource, overriding the `private` the library wrote, and a shared HTTP cache (CDN or reverse proxy) sits in front of that route. An application that sets no `Cache-Control` of its own keeps the library's `private` and is not affected.
- Published
- unknown
- Last Modified
- unknown
CVSS details not available.
No product information available.
- https://github.com/ZenHive/mpp/security/advisories/GHSA-82qh-vrvm-gqvc
- https://cna.erlef.org/cves/CVE-2026-89186.html
- https://github.com/ZenHive/mpp/commit/2d4d1d94aae7790ae0623063961adbeef171fa71
- https://github.com/ZenHive/mpp/commit/2fd91a5ecbd0b0ad2a4ac202b79659e8126dbc0b
- https://hex.pm/packages/mpp
No linked vulnerabilities found.
{
"affected": [
{
"database_specific": {
"source": "https://cna.erlef.org/osv/EEF-CVE-2026-89186.json"
},
"package": {
"ecosystem": "Hex",
"name": "mpp",
"purl": "pkg:hex/mpp"
},
"ranges": [
{
"events": [
{
"introduced": "0.1.0"
},
{
"fixed": "0.16.2"
}
],
"type": "SEMVER"
}
],
"versions": [
"0.1.0",
"0.1.1",
"0.10.0",
"0.11.0",
"0.12.0",
"0.13.0",
"0.14.0",
"0.15.0",
"0.16.0",
"0.16.1",
"0.2.0",
"0.3.0",
"0.3.1",
"0.3.2",
"0.4.0",
"0.6.0",
"0.6.1",
"0.6.2",
"0.6.3",
"0.6.4",
"0.7.0",
"0.8.0",
"0.9.0"
]
},
{
"database_specific": {
"source": "https://cna.erlef.org/osv/EEF-CVE-2026-89186.json"
},
"ranges": [
{
"events": [
{
"introduced": "2d4d1d94aae7790ae0623063961adbeef171fa71"
},
{
"fixed": "2fd91a5ecbd0b0ad2a4ac202b79659e8126dbc0b"
}
],
"repo": "https://github.com/ZenHive/mpp",
"type": "GIT"
}
],
"versions": [
"v0.16.1",
"v0.16.0",
"v0.15.0",
"v0.14.0",
"v0.13.0",
"v0.12.0",
"v0.11.0",
"v0.10.0",
"v0.9.0",
"v0.8.0",
"v0.7.0",
"v0.6.4",
"v0.6.3",
"v0.6.1",
"v0.6.0",
"v0.5.1",
"v0.4.0",
"v0.3.0",
"v0.2.0",
"v0.1.0"
]
}
],
"aliases": [
"CVE-2026-89186",
"GHSA-82qh-vrvm-gqvc"
],
"credits": [
{
"name": "E.FU",
"type": "FINDER"
},
{
"name": "E.FU",
"type": "REMEDIATION_DEVELOPER"
},
{
"name": "Jonatan Männchen / EEF",
"type": "COORDINATOR"
}
],
"database_specific": {
"capec_ids": [
"CAPEC-204"
],
"cpe_ids": [
"cpe:2.3:a:ZenHive:mpp:*:*:*:*:*:*:*:*"
],
"cwe_ids": [
"CWE-524"
]
},
"details": "## Summary\n\nUse of Cache Containing Sensitive Information in ZenHive mpp allows a shared HTTP cache to store a paid response and serve it to clients that never paid.\n\n`MPP.Plug.verify_credential` in `lib/mpp/plug.ex` sets `payment-receipt` and `cache-control: private` on the connection before the wrapped application runs, and registers no `register_before_send/2` callback. `Plug.Conn.put_resp_header/3` replaces an existing header, so a mounting application that sets its own `cache-control` on the paid resource (for example `public, max-age=3600`) silently overrides the `private` the library relies on, and a CDN or reverse proxy can then store the paid 200 together with its `Payment-Receipt` and serve both to unpaid clients. The library-level guarantee is therefore defeatable by the application it protects. For the same reason a downstream non-2xx response still carried `Payment-Receipt`, issuing a receipt for a response that delivered no resource.\n\nThis issue affects mpp: from 0.1.0 before 0.16.2.\n\n## Impact\n\nAn unpaid client requesting the same URL through the shared cache receives the cached paid response, including the `Payment-Receipt` header issued to the paying client. Operators lose the revenue for every cache hit, and the receipt identifying a paid transaction is disclosed to third parties.\n\n## Workarounds\n\nIn the application mounted behind `MPP.Plug`, stop setting `Cache-Control` on paid routes so the library's `private` survives to the response, or set a directive that is itself safe for a shared cache (`private`, or `no-store`). Where the application must set its own caching policy, configure the CDN or reverse proxy not to cache responses carrying a `Payment-Receipt` header.\n\n## Configurations\n\nReachable only where the application mounted behind `MPP.Plug` sets its own `Cache-Control` on the paid resource, overriding the `private` the library wrote, and a shared HTTP cache (CDN or reverse proxy) sits in front of that route. An application that sets no `Cache-Control` of its own keeps the library's `private` and is not affected.",
"id": "EEF-CVE-2026-89186",
"modified": "2026-09-16T08:40:58.908314385Z",
"published": "2026-09-16T08:24:15.058Z",
"references": [
{
"type": "ADVISORY",
"url": "https://github.com/ZenHive/mpp/security/advisories/GHSA-82qh-vrvm-gqvc"
},
{
"type": "WEB",
"url": "https://cna.erlef.org/cves/CVE-2026-89186.html"
},
{
"type": "WEB",
"url": "https://github.com/ZenHive/mpp/commit/2d4d1d94aae7790ae0623063961adbeef171fa71"
},
{
"type": "FIX",
"url": "https://github.com/ZenHive/mpp/commit/2fd91a5ecbd0b0ad2a4ac202b79659e8126dbc0b"
},
{
"type": "PACKAGE",
"url": "https://hex.pm/packages/mpp"
}
],
"schema_version": "1.9.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "mpp writes Payment-Receipt and Cache-Control before the wrapped application runs, letting a consumer's own Cache-Control expose paid responses to shared caches"
}