# Anyone Can Arbitrarily Call FSDVesting.updateVestedTokens()

FSDVesting.updateVestedTokens() lacked caller authentication, letting anyone spoof _user==beneficiary to inflate vested amounts, enabling early full withdrawal or DoS of claims.

- Payout: Audit contest
- Severity: high
- Program: FairSide
- Found by: leastwood
- Disclosed: 2021-12-16
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-11-fairside-findings/issues/101
- Library page: https://bugbountylibrary.com/r/c4%3A2021-11-fairside%3AH-01
- Tags: area:web3 domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** FSDVesting.sol vesting contract
**Root cause:** updateVestedTokens() only checks _user == beneficiary, but _user is caller-controlled, and no check ensures the caller is the trusted FSD.sol contract.
**Steps:**
1. Call `updateVestedTokens(beneficiary, largeAmount)` with `_user` set to your own beneficiary address to pass the `_user == beneficiary` check.
2. Vested amount is inflated; `calculateVestingClaim()` now returns a larger claimable amount.
3. Call `claimVestedTokens()` to withdraw the inflated amount early, or inflate so high that `safeTransfer()` fails for other beneficiaries, blocking their claims.
**How found:** Manual code review of FSDVesting.sol; noticed updateVestedTokens relies on a user-supplied _user argument for its only access check and lacks a caller whitelist.
**Exploitation:** Attacker calls updateVestedTokens with their own address as _user and an arbitrary amount, bypassing the beneficiary check; then claims the inflated vested balance early or griefs other beneficiaries by making safeTransfer revert on insufficient balance.
**Insight:** When an access check compares a function argument to a stored value, verify the argument isn't attacker-controlled; here _user==beneficiary is trivially satisfiable by the caller, so the real missing control is msg.sender authentication.
