# NibblVault: In the buy function, users can avoid paying fees

NibblVault.buy skips the secondary-curve fee when msg.value exceeds the lower-curve diff, letting buyers avoid curator/admin fees.

- Payout: Audit contest
- Severity: medium
- Program: Nibbl
- Found by: cccz
- Disclosed: 2022-08-01
- Write-up quality: 6/10
- Original: https://code4rena.com/reports/2022-06-nibbl#m-06
- Library page: http://bugbountylibrary.com/r/c4%3A2022-06-nibbl%3AM-06
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity vuln:business-logic vuln:fee-bypass

**Target:** NibblVault.buy function (Solidity vault contract)
**Root cause:** In the msg.value > _lowerCurveDiff branch, the secondary curve portion is settled by directly incrementing secondaryReserveBalance instead of calling _buySecondaryCurve, so the fee that _buySecondaryCurve would charge is never collected.
**Steps:**
1. Call `buy` with `msg.value` greater than `_lowerCurveDiff` (the amount needed to exhaust the secondary curve).
2. The else branch executes: `secondaryReserveBalance += _lowerCurveDiff;` with no fee charge.
3. Only the primary curve portion `msg.value - _lowerCurveDiff` goes through `_buyPrimaryCurve`, which charges its fee.
4. The secondary-curve fee is skipped entirely, leaking value from curator/admin.
**How found:** Code review of the buy function's branch logic: noticed the commented-out `_buySecondaryCurve` call replaced by a direct `secondaryReserveBalance += _lowerCurveDiff`, meaning the fee logic inside _buySecondaryCurve is bypassed.
**Exploitation:** A buyer sizes the purchase so msg.value exceeds the lower-curve diff, routing the secondary-curve portion through the fee-free direct reserve update and paying fees only on the primary-curve remainder.
**Insight:** When a gas-optimization refactor inlines a curve purchase as a direct reserve increment, check whether the inlined path still replicates the fee/accounting side effects of the function it replaced.

