CVE-2026-89186: 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
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.verifycredential in lib/mpp/plug.ex sets payment-receipt and cache-control: private on the connection before the wrapped application runs, and registers no registerbeforesend/2 callback. Plug.Conn.putrespheader/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.
Affected Software
Event History
Frequently Asked Questions
Which deployments are exposed to paid-response disclosure through shared caches?
Deployments using mpp versions from 0.1.0 before 0.16.2 are exposed if the mounting application sets a cache-control value on a paid resource that permits shared caching, such as "public, max-age=3600," and a CDN or reverse proxy honors it.
What does an attacker need to do to obtain a paid response without paying?
An unpaid client only needs to request a paid response that was previously stored by a shared HTTP cache. The cached response can include both the paid 200 response and its Payment-Receipt.
Are applications safe if they leave Cache-Control handling entirely to mpp?
The described cache-disclosure condition depends on the mounting application overriding mpp's "cache-control: private" header. The issue occurs because mpp sets that header before the wrapped application runs and does not restore it before sending the response.
How can operators identify potentially affected routes?
Review paid routes for application-level Cache-Control headers that replace mpp's private directive, especially headers allowing public or shared caching. Also check CDN and reverse-proxy caches for stored paid 200 responses carrying a Payment-Receipt.
What should be addressed besides cacheable successful responses?
Downstream non-2xx responses could still carry a Payment-Receipt in affected versions, even though no resource was delivered. Review error responses on protected routes for this header as well.