GHSA-VJ8P-HP9X-GH47
Vulnerability from github – Published: 2026-09-25 21:47 – Updated: 2026-09-25 21:47Vulnerability
When the server acts as the fee payer, mpp Elixir 0.4.0 (ZenHive/mpp) does not validate whether the gas_limit set by the client is enough before broadcasting. A malicious client can drain the server's gas without paying.
A transferWithMemo call on Tempo Moderato testnet requires ~51,299 gas to complete successfully. By setting gas_limit = 51,298:
- The Tx gets cosigned and broadcast by the server.
- The Tx runs out of gas during EVM execution. All state reverts.
- The server's fee-payer wallet is charged for gas used.
- The client pays nothing and receives no resource.
# Run the PoC
unzip mpp_elixir_low_gas_PoC.zip
cd mpp_elixir_low_gas_PoC
docker build -t mpp-elixir-low-gas .
docker run --rm mpp-elixir-low-gas
Zero-Cost DoS Attack: Unlike gas draining with access list or padding, where the malicious client needs to complete a payment to drain the gas, this vulnerability allows malicious users to continuously drain the server's gas at virtually no financial cost (requiring only computing power). Therefore, an attacker can spawn N malicious clients to completely drain the funds from the server's wallet to perform a Denial of Service (DoS) attack. Once the server's wallet is empty, it has no more funds to pay the gas fees for upcoming requests from legitimate clients.
# Run the DoS PoC
unzip mpp_elixir_low_gas_dos_PoC.zip
cd mpp_elixir_low_gas_dos_PoC
docker build -t mpp-elixir-dos .
docker run --rm mpp-elixir-dos
Vulnerable code path: broadcast_and_verify/7 in mpp/methods/tempo.ex (ZenHive/mpp 0.4.0).
When wait_for_confirmation = true (the default), it calls rpc_broadcast_sync directly without any gas-adequacy check or simulation. The alternative wait_for_confirmation = false path does call simulate_payment_call via eth_call, but that simulation omits the gas parameter and therefore does not catch out-of-gas conditions.
Impact
A malicious client can drain the server's wallet without any financial cost.
{
"affected": [
{
"package": {
"ecosystem": "Hex",
"name": "mpp"
},
"ranges": [
{
"events": [
{
"introduced": "0.2.0"
},
{
"fixed": "0.6.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-20"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-25T21:47:36Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Vulnerability\nWhen the server acts as the fee payer, `mpp` Elixir 0.4.0 (ZenHive/mpp) does not validate whether the `gas_limit` set by the client is enough before broadcasting. A malicious client can drain the server\u0027s gas without paying.\n\nA `transferWithMemo` call on Tempo Moderato testnet requires **~51,299 gas** to complete successfully. By setting `gas_limit = 51,298`:\n\n1. The Tx gets cosigned and broadcast by the server.\n2. The Tx runs out of gas during EVM execution. All state reverts.\n3. The server\u0027s fee-payer wallet is charged for gas used.\n4. The client pays nothing and receives no resource.\n\n```bash\n# Run the PoC\nunzip mpp_elixir_low_gas_PoC.zip\ncd mpp_elixir_low_gas_PoC\ndocker build -t mpp-elixir-low-gas .\ndocker run --rm mpp-elixir-low-gas\n```\n\n**Zero-Cost DoS Attack:** Unlike gas draining with `access list` or `padding`, where the malicious client needs to complete a payment to drain the gas, this vulnerability allows malicious users to continuously drain the server\u0027s gas at virtually no financial cost (requiring only computing power). Therefore, an attacker can spawn *N* malicious clients to completely drain the funds from the server\u0027s wallet to perform a Denial of Service (DoS) attack. Once the server\u0027s wallet is empty, it has no more funds to pay the gas fees for upcoming requests from legitimate clients. \n\n```bash\n# Run the DoS PoC\nunzip mpp_elixir_low_gas_dos_PoC.zip\ncd mpp_elixir_low_gas_dos_PoC\ndocker build -t mpp-elixir-dos .\ndocker run --rm mpp-elixir-dos\n```\n\n**Vulnerable code path:** `broadcast_and_verify/7` in `mpp/methods/tempo.ex` (ZenHive/mpp 0.4.0).\nWhen `wait_for_confirmation = true` (the default), it calls `rpc_broadcast_sync` directly without any gas-adequacy check or simulation. The alternative `wait_for_confirmation = false` path does call `simulate_payment_call` via `eth_call`, but that simulation omits the `gas` parameter and therefore does not catch out-of-gas conditions.\n\n## Impact\nA malicious client can drain the server\u0027s wallet without any financial cost.",
"id": "GHSA-vj8p-hp9x-gh47",
"modified": "2026-09-25T21:47:36Z",
"published": "2026-09-25T21:47:36Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/ZenHive/mpp/security/advisories/GHSA-vj8p-hp9x-gh47"
},
{
"type": "WEB",
"url": "https://github.com/ZenHive/mpp/commit/d84e3e528db39654540c2035ea0fbdf7b950d3d1"
},
{
"type": "PACKAGE",
"url": "https://github.com/ZenHive/mpp"
},
{
"type": "WEB",
"url": "https://github.com/ZenHive/mpp/releases/tag/v0.6.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "mpp vulnerable to Gas Draining with low gas limit"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
How durations are calculated
Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.
Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.