VDB
Sign up

EEF-CVE-2026-88255

mpp Tempo keys its pre-broadcast dedup reserve on the caller-supplied transaction encoding, so a re-encoded signed transaction reserves a second slot

Quick fix

EEF-CVE-2026-88255 — mpp: upgrade to the fixed version with the command below.

mix deps.update mpp

Details

## Summary

Improper Validation of Unsafe Equivalence in Input in ZenHive mpp allows an unauthenticated remote client to pass the Tempo duplicate-submission gate twice with one signed transaction.

`MPP.Methods.Tempo` reserves the pre-broadcast dedup slot on the caller-supplied hex in `reserve_hash_atomic/2`, keyed through `store_key/1` on `tx.raw` rather than on a canonical form of the transaction. The deserializer stores the caller's hex verbatim and accepts both recovery-id encodings, so one signed transaction submitted once with `v=27` and once with `v=0` yields two distinct reserve keys, and both pass the reserve and reach the broadcast path. The plug-level credential replay store is deliberately carved out for `tempo` in `lib/mpp/replay.ex`, leaving this reserve as the only gate, and the post-broadcast mark writes the canonical hash key that the raw-keyed reserve never reads.

What the duplicate submission yields depends on the node: a nonce-reuse rejection fails closed, while a node that answers with the canonical hash for an already-known transaction returns a second valid `Payment-Receipt` for a single on-chain payment.

This issue affects mpp: from 0.2.0 before 0.16.2.

## Impact

A client re-encodes the recovery id of a transaction it has already submitted and presents it again. The duplicate passes the only duplicate-submission gate the Tempo method has, and against a node that answers with the canonical hash for an already-known transaction the client is issued a second `Payment-Receipt` for one on-chain payment.

## Configurations

Reachable when `MPP.Methods.Tempo` broadcasts a `type="transaction"` credential with a dedup store in place. From mpp 0.7.0 the dedup store is on by default (the app-started `MPP.Tempo.ConCacheStore`; opt out with `store: false`), so every default Tempo deployment from 0.7.0 before 0.16.2 is affected. Before 0.7.0 the default store was `nil`, which runs the library statelessly and provides no application-level replay protection at all, a documented property rather than part of this issue; those versions are affected only where a `"store"` was configured explicitly in `method_config`.

Are you affected?

Enter the version of the package you're using.

Affected packages

Hex/mpp
Introduced in: 0.2.0Fixed in: 0.16.2
Fixmix deps.update mpp

References