# Agent underlying balance can be inflated, which cannot be prove-able to challenge it as illegal.

Agent pays redemption amount to own address using the redemption payment reference before the request's firstUnderlyingBlock, then tops up; both illegalPaymentChallenge and freeBalanceNegativeChallenge revert, inflating underlying balance.

- Payout: Contest reward
- Severity: medium
- Program: Flare
- Credited: farman1094
- Disclosed: 2025-11-27
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-08-flare-fasset#m-02
- Library page: https://bugbountylibrary.com/r/c4%3A2025-08-flare-fasset%3AM-02
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** CoreVaultClientFacet / RedemptionConfirmationsFacet / ChallengesFacet (FAsset asset manager)
**Root cause:** confirmRedemptionPayment requires payment blockNumber >= request.firstUnderlyingBlock, so a payment made with the redemption's payment reference before the request is created cannot be proven as the redemption payment; meanwhile illegalPaymentChallenge reverts on MatchingRedemptionActive and freeBalanceNegativeChallenge subtracts the open redemption's underlyingValueUBA from spentAmount, netting to zero.
**Steps:**
1. Read state slot 14 (newRedemptionRequestId, uint64) on-chain to predict the next redemption request id.
2. Predict PaymentReference.randomizedIdSkip from block number to compute the future payment reference.
3. Agent sends a payment of request.valueUBA to an own address using that predicted redemption payment reference, before the redemption request exists.
4. Agent calls CoreVaultClientFacet::transferToCoreVault to create the redemption request with the same payment reference.
5. Attempt ChallengesFacet::illegalPaymentChallenge(agent, txHash) -> reverts `MatchingRedemptionActive` because redemption is open.
6. Attempt ChallengesFacet::freeBalanceNegativeChallenge(agent, [txHash]) -> reverts `MultiplePaymentsChallengeEnoughBalance` because spentAmount - redemptionValueUBA nets to zero.
7. Redemption defaults via RedemptionDefaultsFacet::executeDefaultOrCancel; status DEFAULTED is still isOpen, so balance stays inflated and agent mints more FAsset.
**How found:** Reasoned about the ordering constraint in confirmRedemptionPayment (payment blockNumber >= firstUnderlyingBlock) versus the challenge logic: illegalPaymentChallenge skips open redemptions and freeBalanceNegativeChallenge subtracts open redemption value from spentAmount, so a pre-request self-payment with the correct reference is unprovable. Predicted request id from storage slot 14 and randomizedIdSkip from block number.
**Exploitation:** Agent with a redemption obligation pays the redemption amount to a self-controlled underlying address using the redemption's payment reference before the request's firstUnderlyingBlock. The payment cannot be submitted as redemption proof (blockNumber check) and cannot be challenged (both challenge paths revert), so the agent's underlying balance appears intact while it retains the funds, enabling further FAsset minting without backing.
**Insight:** When a protocol distinguishes 'payment before request' from 'payment after request' via block-number checks, look for a window where a self-payment with the future payment reference is neither provable as redemption nor challengeable as illegal; also check that challenge accounting doesn't net out open redemption value against the same payment.
