# Public ContributionNft::mint leads to cascading issues / loss of funds

Unguarded ContributionNft::mint lets proposers supply bogus coreId, datasetId, isModel and URI, corrupting ServiceNft impacts and reward/mint payouts.

- Payout: Contest reward
- Severity: high
- Program: Virtuals Protocol
- Credited: YouCrossTheLineAlfie
- Disclosed: 2025-08-04
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-04-virtuals-protocol#h-04
- Library page: https://bugbountylibrary.com/r/c4%3A2025-04-virtuals-protocol%3AH-04
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:solidity technique:chained technique:source-review vuln:access-control vuln:accounting-error vuln:business-logic

**Target:** ContributionNft / ServiceNft / AgentRewardV2 / Minter contracts
**Root cause:** ContributionNft::mint only checks msg.sender is the proposal proposer, not that caller is admin/operator, and never validates coreId, datasetId, isModel_, parentId or tokenURI against the proposal.
**Steps:**
1. Submit a proposal via the governor so msg.sender == proposalProposer(proposalId).
2. Call `ContributionNft::mint(to, virtualId, coreId, newTokenURI, proposalId, parentId, isModel_, datasetId)` with attacker-chosen coreId/datasetId/isModel_/parentId.
3. ServiceNft::mint reads getCore(proposalId) and isModel(proposalId) from the corrupted contribution NFT, setting wrong _cores and routing to _coreServices vs _coreDatasets.
4. ServiceNft::updateImpact reads getDatasetId(proposalId); if >0 it overwrites _impacts[datasetId] and _maturities[datasetId] of another service.
5. AgentRewardV2::_distributeContributorRewards and Minter::mint consume getImpact, skewing reward distribution and minted token amounts.
**How found:** Read docs stating the frontend calls ContributionNft::mint, then code-read mint and noticed the only guard is proposer identity with no validation of coreId/URI/parentId/isModel_/datasetId; traced each field into ServiceNft, AgentRewardV2, Minter and AgentDAO to show downstream corruption.
**Exploitation:** A proposer mints their own contribution NFT with arbitrary coreId/datasetId/isModel values, poisoning ServiceNft impact and maturity records for their proposal and for an arbitrary victim datasetId, then collects inflated rewards via AgentRewardV2 and inflated mint payouts via Minter while other contributors receive less.
**Escalation:** Cascades from one unguarded mint into ServiceNft state corruption, AgentDAO maturity miscalculation, reward misdistribution and Minter over/under-payment.
**Insight:** When docs say a privileged action is performed 'by the frontend', check whether the contract enforces that privilege; then trace each unvalidated parameter into every consumer (impact, maturity, reward, mint amount) to prove fund impact rather than just bad metadata.
