DeFi Security AllianceRequest an audit
Menu

EVM patterns

ERC3156 Flash Loan Security: Callback Authority and Repayment

Repayment protects the lender's financing boundary, while the receiver must authorize the work performed during the loan. ERC3156 flash loan security requires lender and initiator checks plus the application's own request and allowance policy.

Circular glass conduit carrying blue tokens through a white valve beside two keys, illustrating callback and initiator checks.

Key facts

Original policy grid
64 logical inputs across 6 illustrative Boolean conditions
Lender-only policy
32 accepted inputs, including 31 outside full illustrative policy
Lender and initiator
16 accepted inputs, including 15 outside full illustrative policy
Full illustrative policy
1 of 64 logical inputs accepted; not a normative ERC3156 control count
Limit
No EVM, loan, callback or token transfer executed

Follow the receiver rather than the borrowed balance

A lender can receive repayment while a borrower executes an unauthorized action.

ERC3156 flash loan security requires the receiver to authenticate its callback and bind the requested work to its own policy. Atomic repayment protects a lender's financing boundary. It does not certify the business logic that runs while the temporary funds are available.

Consider a receiver that holds tokens and offers a strategy callback. An approved lender calls its onFlashLoan function, but another actor initiated the loan. If the receiver assumes that lender identity also proves approval of the strategy data, it has skipped an authorization decision. This is a constructed teaching scenario; no loss or deployed exploit is asserted.

A flash loan callback is the receiver's execution step after the lender supplies the temporary tokens. ERC3156 defines a single-asset interface with a callback, a return-value check and repayment of principal plus fee. It distinguishes the callback caller from the initiator: the lender calls the receiver, while the initiator is whoever called the lender's flashLoan function.

Actors and values in an ERC3156 receiver review
ElementMeaningReceiver question
Callback callerThe contract invoking the receiverIs this an approved lender?
InitiatorThe caller that requested the lender's loanMay this actor request the receiver's work?
ReceiverThe contract executing the callbackWhich balances and authorities can it use?
Callback dataReceiver-specific action informationWas this exact action authorized?

The ERC3156 specification recommends checking an approved lender before treating callback fields as genuine, then a trusted initiator before trusting the provenance of callback data. Its reference borrower uses the narrower policy that the initiator must be the borrower itself. Other applications can intentionally permit different initiators, but that permission needs an explicit rule.

Our broader flash loan attack guide examines temporary capital and downstream protocol state. Here the reader's job is narrower: review who can make a receiver act and approve repayment. That job remains relevant even when the strategy contains no oracle interaction and the temporary loan is fully repaid.

Start from the receiver's assets and permissions. A callback might trade, approve a spender or invoke a privileged function. The review needs to follow those effects under the receiver's identity. A familiar lender address does not establish that every possible use of those permissions is intended.

Original callback acceptance grid

Method

We defined an illustrative receiver policy with six independently supplied Boolean conditions, then enumerated the complete input product. The policy requires an approved lender, authorized initiator, requested token, requested amount, approved fee bound and matching request data. These are our teaching fixtures, not six mandatory ERC3156 requirements.

Mechanism sources
ERC3156 and OpenZeppelin Contracts v5.4.0 flash-mint source, retrieved on .
Population
Both values for each of six policy conditions, producing 64 logical input cases.
Compared predicates
Lender-only acceptance, lender-plus-initiator acceptance and the full illustrative conjunction.
Exclusions and missing cases
None within the declared finite grid. Each input row is retained.
Artifacts
seo/research/integration-boundaries-2026-10-11/support-execution/finite-models.py and erc3156-flash-loan-security-model-2026-10-11.json, with the complete CSV ledger. These are repository artifacts, not public downloads.

Results

Acceptance under the complete illustrative grid, measured
Acceptance policyAccepted casesAccepted outside full policy
Approved lender only32 of 6431
Approved lender and initiator16 of 6415
All illustrative conditions1 of 640

This arithmetic separates identity checks from action constraints. Adding initiator authorization reduces the admitted population but does not bind the remaining action fields in this model. A real borrower might accept several tokens or an amount range rather than exact equality. Its full policy would then define a different accepted set.

Limits

  • No EVM, token transfer or callback ran. Inputs are logical fixtures and the outputs are policy decisions.
  • Independence is deliberate. A correct lender already constrains some callback fields, so every logical combination need not be reachable through that lender.
  • The outside-policy counts are not vulnerabilities, attacks or deployed failure rates. They apply only to our declared illustrative policy.

Our result is useful as a review question: what does an authenticated callback still need to prove before the receiver spends its balances or grants approval? The full answer belongs to the application. The standard provides actor relationships, while the receiver defines which requested actions are permitted.

Authenticate the lender and the initiator

Checking the lender establishes the provenance of the callback fields only under that lender's correct implementation and trust assumptions. ERC3156 requires the lender to pass token, amount and data without modification, supply the specified initiator and use the fee returned by flashFee. Those guarantees do not identify who the receiver intended to authorize.

The next check is the initiator. If the receiver initiates its own loans, the reference policy initiator == address(this) may fit. A shared receiver or routed application may intentionally allow another contract. Record that actor and the scope of its authority instead of weakening the check to accommodate every caller.

Lender identity and requested work are separate checksA receiver first checks the callback caller, then the initiator and authorized request. Repayment approval follows the accepted action. The lender's callback return check does not replace those receiver decisions.Approved lenderAuthorized requestRepayment approvalSuccessful lender settlement cannot certify receiver policy
The receiver owns the action-authorization decision before it exposes repayment authority.
Caller trust
The callback contract is an approved lender with the expected interface behavior.
Initiator trust
The actor that requested the loan is authorized to invoke this receiver workflow.
Request binding
The supplied action matches the receiver's accepted request or explicitly permitted policy.

Decode untrusted action data only within the intended authorization sequence. The reference borrower checks lender and initiator before decoding its callback data. An application may need preliminary parsing to locate a policy field, but parsing is not approval. Make the point where the data becomes authoritative explicit in the control flow.

Do not use the callback's return hash as proof of borrower safety. The lender requires the prescribed hash to recognize a successful interface response. A receiver can return that value after performing an unintended action. The hash check and the receiver's business invariant answer different questions.

Also inspect any way to invoke the callback directly. A caller can supply plausible-looking token, amount, fee and initiator values without transferring a loan. A direct callback test should demonstrate rejection at the lender guard using otherwise valid business fixtures. If it fails earlier due to malformed data, it has not exercised the intended authority check.

Lender upgrades or trust-list changes can alter the receiver's assumption. Identify the authority that changes the accepted lender and decide whether outstanding requests remain valid after that change. This is a deployment-specific policy question, not an automatic property of the ERC3156 interface.

Bind repayment to the approved action

The standard requires the receiver to approve principal plus fee to the callback caller before the callback finishes, so the lender can collect repayment. This creates an allowance boundary. Verify the amount, spender and timing against the accepted request, rather than treating repayment approval as harmless because the loan is temporary.

ERC3156's security discussion warns about trusted initiators both when a receiver maintains an approval and when it grants one during the callback. A long-lived allowance can give a later request access to funds beyond the receiver's intended action. The exact risk depends on lender behavior and receiver policy; an allowance alone is not proof of an exploit.

OpenZeppelin's pinned flash-mint implementation shows one settlement composition. It mints to the receiver, checks the callback return, spends allowance and burns principal or principal plus fee. With a nonzero fee receiver, it burns principal and transfers the fee separately. Its default fee is zero. Other ERC3156 lenders can lend preexisting balances instead of minting.

Repayment evidence and its limits
EvidenceWhat to inspectWhat it does not establish
Repayment allowanceApproved spender and bounded amountAuthorization of strategy data
Correct callback returnLender-side interface checkReceiver business invariant
Principal and fee collectedLender settlement pathSafety of downstream pool interactions
Flash-mint supply reconciledPinned mint and burn accountingCompatibility of every token extension

Choose the fee policy before action execution. It may use a fixed supported lender quote, an approved cap or another explicit rule. A caller-controlled fee that is never checked against the request can expand repayment authority. Our model uses a Boolean approved-fee condition and does not recommend a universal cap.

Maximum-loan query and fee query have different unsupported-token behavior in the standard. maxFlashLoan returns zero for an unsupported token, while flashFee reverts. An adapter should distinguish unsupported capability from a transport failure and from a supported loan that exceeds its maximum. Do not convert every negative observation into the same liquidity message.

OpenZeppelin warns that its default flash-mint maximum needs an override for capped-token compositions such as the cited cap-sensitive extensions. A mathematically large maximum is not automatically a usable amount under all inherited constraints. Pin the composed token implementation and test the actual boundary.

Approval cleanup is an application requirement to define and verify. Inspect residual allowance after successful settlement and after relevant failure paths in the actual token/lender pair. A conventional ERC20 expectation should not be generalized to every token without checking its behavior.

Keep capability discovery separate from execution evidence. A maximum-loan query reports a supported bound, and a fee query reports its corresponding charge. Neither transfers tokens or demonstrates that this receiver can repay. The actual loan call must follow its callback and settlement requirements and return success. Preserve the query results as prerequisites alongside the completed transaction's own evidence.

Supply reconciliation needs the fee branch, not a blanket restored-supply assertion. For the pinned flash-mint implementation, a zero fee leaves the original supply after principal is burned. A nonzero fee sent to a separate fee receiver also leaves the original supply while moving fee tokens. If that nonzero fee is instead burned with principal, supply ends below its original value by the fee. These are source-derived branch expectations, not measurements of executed loans.

The receiver must have the tokens needed for its fee as well as the borrowed principal. Define where those tokens come from in a test fixture. A strategy that produces enough repayment tokens in one case may fail in another. Keep the funding precondition visible so a fee branch is not diagnosed as a callback-authorization error.

Inspect the final supply and balance assertions together. When fees are transferred, the expected fee-receiver change belongs in the accounting record. When fees are burned, the supply change belongs there instead. A single assertion that the lender received its amount cannot distinguish the intended token-accounting branch.

Token extensions make those expectations application-specific. A capped or vote-sensitive composition may constrain the usable flash-mint maximum differently from the base calculation. Test the composed maximum and a neighboring rejected amount with otherwise valid callback data. That positive control distinguishes a supported amount boundary from a borrower that always fails because it cannot repay.

A retained settlement fixture can later reveal changes caused by a fee override, a new fee receiver or a token hook. Record those configuration and source dependencies as review triggers. The callback identity matrix remains useful, but it cannot certify the accounting assumptions of a changed token composition.

Test callbacks, approvals and nested execution

Use an accepted loan request as the control fixture. Keep balances, lender configuration and action data valid while changing one authorization condition. The resulting failure should identify the intended check. A borrower that rejects every call due to a missing balance can pass a superficial unauthorized-initiator test without enforcing initiator policy.

  1. Establish the permitted lender, initiator, token, amount rule, fee policy and requested action before starting the loan.
  2. Call the callback directly from an unapproved address with otherwise valid parameters. Confirm the caller guard is the failing condition.
  3. Use the approved lender with an unauthorized initiator, then repeat with the permitted initiator as the positive control.
  4. Alter a material action field while preserving the actor checks. Verify that the receiver cannot reuse approval for a different action.
  5. Exercise incorrect callback return, callback revert and failed repayment in the actual implementation. Inspect the final application and allowance state.
  6. Reconcile the completed transaction with the business invariant, not only the lender's repayment result.

Nested execution deserves a policy of its own. A strategy may intentionally request another loan or call an external pool that calls back into the receiver. Determine whether the in-progress request state is frame-specific, shared or deliberately locked. A single stored expected amount can be overwritten by a nested workflow unless the design prevents or distinguishes it. This is a test recommendation, not an observed finding in the finite grid.

Reentrancy protection should fit the receiver's state transitions. The reentrancy analysis explains why external calls must be examined with the state they can observe or change. A lender guard identifies a caller; it does not automatically prevent that caller's authorized path from invoking unguarded receiver functions.

Check both the loan wrapper's atomic outcome and the application assertions. A reverted transaction can restore state, while a successful transaction may preserve an unintended trade or authority change. The test should state which outcome is expected and why, then inspect the relevant balances and permissions after it.

A fork can supply a real lender and token configuration, but it still reflects the chosen block and test inputs. Preserve the code versions, addresses and block reference. Supplement that realistic fixture with boundary cases absent from the selected state, including unsupported tokens and fee changes where the implementation permits them.

Explain what the borrower review establishes

A receiver review should produce an authorization map, request-binding tests and repayment evidence. Name the supported lenders and token behaviors, the initiators allowed to request work and the application effects permitted during the callback. List nested-call assumptions and residual allowance policy beside the test results.

The security provider directory and Pharos Production member profile can help select an independent reviewer. Give the reviewer the receiver and its strategy dependencies, rather than a lender interface alone. The lender's correct repayment mechanism cannot establish that a receiver's external trades preserve its own accounting.

Keep the original grid in its role as an explanatory artifact. Its lender-only predicate admitted 31 cases outside our complete illustrative policy. That count shows why authentication and action authorization need separate reasoning; it does not count reachable attacks. Application tests must supply the actual allowed set and demonstrate the relevant behavior.

A useful public conclusion is therefore specific: the receiver authenticates its callback context, constrains its requested action and grants repayment authority under stated assumptions. The evidence packet should make each of those statements inspectable. Repayment alone supports a narrower conclusion.

Frequently asked questions

Does ERC3156 standardize a simultaneous multi-asset loan?

The cited standard covers single-asset flash loans. A multi-asset interface or nested composition needs its own review; do not infer its callback semantics from a similar function name.

Can an application use a flash loan without an oracle?

Yes. The financing interface does not require an oracle. Review whatever state and external effects the receiver's actual strategy uses rather than force an oracle checklist onto every borrower.

Does the default zero fee make a flash-mint operation costless?

The pinned default flash fee is zero, but that is distinct from transaction execution costs and any application effects. Do not advertise a total-cost guarantee from the fee function alone.

Comments

0

    Leave a comment

    Share a question or observation about this article.

    10 to 3,000 characters.