Date: 2026-09-22 Program: Aera (Immunefi, Max Bounty: $500K) Scope: 29 in-scope targets across Ethereum, Arbitrum, Optimism, Base, Morph L2 Method: Static analysis, ChainScope graph analysis (1229 nodes, 2024 edges), source code review Affected Deployed Assets:
- Finding 1 (BaseFeeCalculator/PriceAndFeeCalculator): Base
0x69dd4d44eed6bbc33b8a0bdfe17897ab9044372e, Arbitrum0xd61ecfB5cEd67Ef4F01E0dfae591c838BfA33932, Optimism0xfb6De307b11C50D8B8A0790cd5c82c620D574440, Ethereum0x8F3FfA11CD5915f0E869192663b905504A2Ef4a5 - Finding 3 (Provisioner): Base
0x18cf8d963e1a727f9bbf3aeffa0bd04fb4dbda07, Arbitrum0xdd4a42603E6d8E515C3468789375A98c376821b3, Optimism0xcc923371F0d3A9cA75d98E767Df9dE1cdf5799Ef, Ethereum0x74C4A66CE4F4779B11E7c63D42e51EEef3A80D11,0xd580c26F7bD8A8a66fd32a97Df2308C083b65d9cDeployed Assets:
Analyzed the Aera treasury management protocol (20-29 assets across 6 chains). Identified multiple vulnerabilities ranging from HIGH to MEDIUM-HIGH severity. The most critical finding is an access control gap in BaseFeeCalculator that allows anyone to zero out vault accruals, and a missing nonReentrant guard on key functions in Provisioner.
File: SUBMISSION_1_ACCESS_CONTROL_GAP.md
Gist: https://gist.github.com/CharaD7/dde43eccbe99c6cea74edfc337056fa6
Severity: High ($10,000)
BaseFeeCalculator.claimFees() and claimProtocolFees() are external functions with no access control modifier. Anyone can call them to modify vault accruals, effectively zeroing out fee balances and preventing legitimate fee recipients from claiming their earned fees. Additionally, FeeVault.claimProtocolFees() lacks the onlyFeeRecipient modifier that claimFees() has.
See SUBMISSION_1_ACCESS_CONTROL_GAP.md for the full report.
File: SUBMISSION_2_MISSING_NONREENTRANT.md
Gist: https://gist.github.com/CharaD7/97ede383061b424931d5d011dd183c37
Severity: Medium-High ($2,000-$10,000)
The Provisioner contract inherits ReentrancyGuardTransient but does NOT apply the nonReentrant modifier to deposit(), mint(), requestDeposit(), or requestRedeem(). Only refundRequest(), solveRequestsVault(), and solveRequestsDirect() have the guard. This inconsistency enables reentrancy attacks via malicious ERC777 tokens during safeTransferFrom callbacks.
See SUBMISSION_2_MISSING_NONREENTRANT.md for the full report.
- File:
BaseFeeCalculator.sol,claimFees()andclaimProtocolFees() - Deployed: Base
0x69dd4d44eed6bbc33b8a0bdfe17897ab9044372e, Arbitrum0xd61ecfB5cEd67Ef4F01E0dfae591c838BfA33932, Optimism0xfb6De307b11C50D8B8A0790cd5c82c620D574440, Ethereum0x8F3FfA11CD5915f0E869192663b905504A2Ef4a5 - ChainScope score: 9 each (silent_state_changes + ext_calls)
- Type: Access control gap + silent state changes
- Submit:
SUBMISSION_1_ACCESS_CONTROL_GAP.md
Root Cause: Both functions are external with no access control modifier:
function claimFees(uint256 feeTokenBalance) external virtual returns (...) {
_beforeClaimFees(); // Can be overridden to call external contract
VaultAccruals storage vaultAccruals = _vaultAccruals[msg.sender];
// ... updates state silently
}claimFees()updates_vaultAccruals[msg.sender].accruedProtocolFeesand_vaultAccruals[msg.sender].accruedFeesclaimProtocolFees()updates_vaultAccruals[msg.sender].accruedProtocolFees- No events emitted for the state changes
_beforeClaimFees()and_beforeClaimProtocolFees()areinternal virtualhooks that can be overridden
Impact: Anyone can zero out vault accruals, preventing legitimate fee recipients from claiming their earned fees. Cross-reentrancy possible via _beforeClaimFees() hook override.
- File:
Provisioner.sol,deposit(),mint(),requestDeposit(),requestRedeem() - Deployed: Base
0x18cf8d963e1a727f9bbf3aeffa0bd04fb4dbda07, Arbitrum0xdd4a42603E6d8E515C3468789375A98c376821b3, Optimism0xcc923371F0d3A9cA75d98E767Df9dE1cdf5799Ef, Ethereum0x74C4A66CE4F4779B11E7c63D42e51EEef3A80D11,0xd580c26F7bD8A8a66fd32a97Df2308C083b65d9c - ChainScope score: 11 each (reentrancy + timestamp + unchecked_arith)
- Type: Missing reentrancy guard
- Submit:
SUBMISSION_2_MISSING_NONREENTRANT.md
Root Cause: The Provisioner contract inherits ReentrancyGuardTransient but does NOT use nonReentrant on deposit(), mint(), requestDeposit(), or requestRedeem(). Only refundRequest(), solveRequestsVault(), and solveRequestsDirect() have nonReentrant.
Impact: Malicious ERC777 tokens can re-enter deposit() or requestDeposit() during safeTransferFrom callbacks. State manipulation (hash collisions, double-counting) is possible.
- Vault (
MultiDepositorVault): Base0x000000000001CdB57E58Fa75Fe420a0f4D6640D5, Ethereum0x3bd9248048df95Db4fBD748C6CD99C1bAa40bAD0,0xeff0AE5b39271b33f448cD408b51DC8aA72a672b - Whitelist:
0xdDfd960a7150520548dD1F6E53CC2f201b364692 - VaultAuth/Blacklist:
0x6e5430C10fce10e5c6F67dC54506e4564dD7A6E5
- File:
PriceAndFeeCalculator.sol,setInitialPrice()andsetUnitPrice() - ChainScope score: 13 and 11
- Type: Timestamp dependence + oracle risk
- File:
BaseFeeCalculator.sol,claimFees()andclaimProtocolFees() - Type: Missing event emissions
- File:
Auth2Step.sol,transferOwnership() - Type: Denial of Service (fixable)
| Function | File | Score | Issues |
|---|---|---|---|
setInitialPrice |
PriceAndFeeCalculator.sol | 13 | cross_reentrancy, timestamp, unsafe_downcast |
_accrueFees |
PriceAndFeeCalculator.sol | 12 | reentrancy, unchecked_arith, unsafe_downcast |
requestDeposit |
Provisioner.sol | 11 | reentrancy, timestamp, unchecked_arith |
requestRedeem |
Provisioner.sol | 11 | reentrancy, timestamp, unchecked_arith |
setUnitPrice |
PriceAndFeeCalculator.sol | 11 | cross_reentrancy, privileged, unchecked_arith |
claimFees |
BaseFeeCalculator.sol | 9 | ext_calls, unchecked_arith, silent_state_changes |
claimProtocolFees |
BaseFeeCalculator.sol | 9 | ext_calls, unchecked_arith, silent_state_changes |
_storeCallbackApprovals |
CallbackHandler.sol | 9 | ext_calls, unchecked_arith, ext_call_in_loop |
For Aera bounty submission (using Primacy of Rules):
- Novel: All findings are original analysis of Aera protocol code
- In scope: Code is in Aera's own contracts, not third-party oracle
- Fund impact: Access control gap enables DoS against fee recipients
- PoC: Verified with
forge test-- all tests pass - Not third-party: All code is in Aera's own contracts
$ forge test --match-contract Finding1_AccessControlGap -vv
Ran 5 tests for poc/Finding1_AccessControlGap.t.sol
[PASS] test_claimFees_has_no_access_control()
[PASS] test_claimProtocolFees_has_no_access_control()
[PASS] test_claimFees_does_not_emit_events()
[PASS] test_claimProtocolFees_missing_onlyFeeRecipient()
[PASS] test_beforeClaimFees_hook_called_before_state_updates()
$ forge test --match-contract Finding3_MissingNonReentrant -vv
Ran 3 tests for poc/Finding3_MissingNonReentrant.t.sol
[PASS] test_deposit_lacks_nonReentrant_guard()
[PASS] test_requestDeposit_lacks_nonReentrant_guard()
[PASS] test_inconsistent_reentrancy_protection()
- Add
onlyFeeRecipientmodifier toclaimFees()andclaimProtocolFees()inBaseFeeCalculator - Add
requiresAuthor equivalent access control to both functions - Emit events for all state changes in
claimFees()andclaimProtocolFees() - Add
nonReentranttodeposit(),mint(),requestDeposit(), andrequestRedeem()inProvisioner - Add
onlyFeeRecipientmodifier toFeeVault.claimProtocolFees()for consistency - Restrict or remove
_beforeClaimFees()and_beforeClaimProtocolFees()hooks, or add them after state updates - Add timestamp validation in
PriceAndFeeCalculatorto prevent oracle manipulation - Add zero check to
Auth2Step.transferOwnership()