# Missing approval bricks token flow

Pull, burn, or safe-mint assumes an allowance or receiver hook that was never granted

_Area: Smart contract access control and control flow. Seen in 16 disclosed reports; one confirmed bounty: $181,850; latest 2025-09-11. Updated 2026-10-23._

## How it works
A flow assumes a token pull will succeed: a contract calls `transferFrom`, `burnFrom`, or a converter that pulls tokens, and the spender must already hold allowance from the owner. Three sub-mechanisms break this: (a) the approval is never issued; (b) it is issued to the wrong spender; (c) the receiving contract cannot accept the token (no receiver hook). The broken assumption is "the allowance exists because the code path exists." Approval is separate state that must be reachable by an authorized caller and executed before the pull. A related inversion: allowance is checked for one side effect but skipped for another, so a pull succeeds without authorization.

## Where it shows up
- `transferFrom`/`burnFrom` with the contract as `from`, no matching `approve` in init or setup [E7](https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.1.1.md)[E8](https://bugbountylibrary.com/r/c4%3A2024-03-canto%3AM-02.md).
- Approval function exists but is gated to a role that cannot reach it [E3](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-11.md).
- External protocol `_safeMint`s an NFT to your contract; no `onERC721Received` [E4](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AH-06.md).
- Delegated pull: router approves the immediate port, but a different contract executes `safeTransferFrom` [E5](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-02.md).
- Cached external address swapped by admin without re-approving [E6](https://bugbountylibrary.com/r/c4%3A2025-08-morpheus%3AM-03.md).
- Adjacent sub-pattern (unauthorized drain, not a brick): allowance checked for one parameter but not a second side effect [E2](https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-54.md), or skipped when both transfer modes are EXTERNAL [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-beanstalk-logic-error-bugfix-review.md).

## How to review
Triage: grep `transferFrom`, `burnFrom`, `_safeMint`, `approve`, and init/setup functions. For every external pull, trace who is `from`, who is `spender`, and where the allowance is set; confirm it is granted on the calling contract by a reachable authorized path before the pull, and that the spender is the contract actually executing the transfer [E5](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-02.md). For receiver hooks, confirm the contract implements the callback and the external mint uses `_safeMint`. For admin-swappable addresses, confirm approvals are refreshed. For multi-parameter functions, verify each allowance-gated side effect is checked independently. Invariant: every pull in a live flow has a corresponding, reachable approval to the exact spender; every safe-mint target implements its receiver.

## Variants seen
- Converter never approved; approve gated away from admin [E3](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-11.md).
- Missing `onERC721Received` blocks unstake [E4](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AH-06.md).
- Router approves local port, RootPort pulls [E5](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-02.md).
- Pool address swapped without re-approval [E6](https://bugbountylibrary.com/r/c4%3A2025-08-morpheus%3AM-03.md).
- `burnFrom` on self without approving the burner [E7](https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.1.1.md).
- Router swaps without approving the DEX [E8](https://bugbountylibrary.com/r/c4%3A2024-03-canto%3AM-02.md).
- Adjacent: allowance skipped when both transfer modes are EXTERNAL [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-beanstalk-logic-error-bugfix-review.md); checked for collateral but not borrow [E2](https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-54.md).

## Why fixes fail
Mocks using `_mint` instead of `_safeMint` mask the missing receiver hook, so tests pass while production reverts [E4](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AH-06.md).

## Impact and severity
Permanent lock of principal or rewards [E3](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-11.md)[E4](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AH-06.md)[E7](https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.1.1.md), broken core functionality [E8](https://bugbountylibrary.com/r/c4%3A2024-03-canto%3AM-02.md), trapped bridged assets [E5](https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-02.md), or unauthorized drains where the check is inverted [E1](https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-beanstalk-logic-error-bugfix-review.md)[E2](https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-54.md). Severity rises when the path is the only exit and no admin recovery exists.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Aimmunefi-com-blog-bug-fix-reviews-beanstalk-logic-error-bugfix-review.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-07-tapioca%3AH-54.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-11.md
- E4: https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AH-06.md
- E5: https://bugbountylibrary.com/r/c4%3A2023-09-maia%3AM-02.md
- E6: https://bugbountylibrary.com/r/c4%3A2025-08-morpheus%3AM-03.md
- E7: https://bugbountylibrary.com/r/cantina%3Azerolend_jan2024%3A3.1.1.md
- E8: https://bugbountylibrary.com/r/c4%3A2024-03-canto%3AM-02.md
