Route Commitment Across Callback Frame and Settlement Envelope
- Name: route commitment across callback frame and settlement envelope
- Category: routing-systems reference / end-to-end execution-authenticity checklist / router-and-solver design note / stage-binding reference
- Summary: Healthy routing systems do not pretend one generic
route hash,path bytes, or solver quote answers every later security question. Two different security objects have to stay pinned end to end. First, the callback frame: which provider, actor, target object, stage, resume path, and payout bucket may still be live when external control returns. Second, the settlement envelope: which counterparty, payer, asset semantics, execution stage, and protocol-authored bytes a downstream consumer may trust when value actually moves. This note exists to keep that split explicit. A route is healthiest when it commits both objects and the transition between them, rather than collapsing them into one ambientexecution is in progressstory. Healthy reviews also keep three promotions separate:a route shell exists,this exact stage-local frame or envelope is canonical right now, andthat canonical stage object still deserves live payer / counterparty / payout authority. Just as importantly, if only one emergency router path, operator-assisted completion lane, or manual fallback route remains live, that surviving route should emit a smaller callback frame and a smaller settlement envelope than healthy-mode routing instead of silently inheriting ordinary payer, counterparty, and payout authority because it is the only path left. - Why this note exists:
- The exploit corpus now has a sharper positive-design note for callback frame truth as a single security object and another for settlement envelope truth as a single security object.
- Modern routers, helpers, solvers, and approval-funded settlement adapters often need both. They open a live callback-capable frame first, then later ask a downstream consumer to trust a settlement envelope.
- The recurring design mistake is to commit only one loose
routeobject and then assume it automatically pins provider, actor, target, stage, payer, pool, and protocol-authored bytes all at once. In practice, those are different joints, and incidents keep showing that one can stay authentic while the other drifts.
The two security objects a route must keep separate
1. Callback frame truth
- This is the in-flight execution object.
- It answers:
which exact callback-capable operation is allowed to resume right now? - The decisive fields are provider identity, actor / beneficiary, target position or object, temporary privilege window, allowed resume path, and the frame-local payout bucket.
- Use callback-frame-truth-security-object when the bug is that a real or plausible callback resumed the wrong still-live authority frame.
2. Settlement envelope truth
- This is the downstream money-moving object.
- It answers:
which exact settlement context is a downstream consumer allowed to trust right now? - The decisive fields are canonical counterparty, payer or inventory source, asset / amount semantics, execution stage, and the exact protocol-authored bytes or typed fields.
- Use settlement-envelope-truth-security-object when the bug is that a downstream consumer trusted the wrong protocol-authored settlement blob, wrong callback caller, or wrong payer / pool context.
3. Why one ambient route object is not enough
- A route can look committed while still leaving the callback frame under-specified:
some flash loan is active,some keeper path is live,some router self-call is allowed. - A route can also look committed while still leaving the settlement envelope under-specified:
the router called,the bytes decode,the pool looks real,the payer field is present. - Safe routing therefore needs both a stage-local callback frame and a stage-local settlement envelope, plus one explicit statement of how the former is allowed to produce the latter.
The six joints a healthy route commitment should keep fused
-
Route identity and version
- The system needs one canonical route or execution-plan identity, plus one parser / serializer version.
- This is the object higher layers approve, sign, quote, or simulate.
- But it is only the outer shell; by itself it does not yet prove which callback frame or settlement envelope is live at a given stage.
-
Stage graph and allowed transitions
- The route must commit which stages can happen and in what order: quote acceptance, flash acquisition, callback settlement, refund, resolver payout, pool callback, or final transfer.
- Healthy systems do not treat
some route is executingas if every later stage is automatically authorized. - The question is always
which stage are we in, and which next stage is actually allowed from here?
-
Frame-opening commitment for callback-capable stages
- Whenever external control can return mid-route, the route must open one explicit callback frame object for that stage.
- That frame needs provider, actor, target, allowed internal selector or payload meaning, and the payout bucket it may mutate.
- This is the joint that keeps f(x), GMX V1, and Exactly-style bugs from reducing to one ambient
callback currently allowedbit.
-
Envelope commitment for downstream settlement stages
- Whenever a downstream resolver, pair, market, or adapter is asked to trust settlement context, the route must also commit one explicit settlement envelope object for that stage.
- That envelope needs canonical counterparty, payer, token semantics, stage meaning, and one stable layout or typed structure.
- This is the joint that keeps 1inch, Sushi RouteProcessor2, ParaSwap Augustus V6, and Primitive-style bugs from reducing to
the router probably meant these bytes.
-
Frame-to-envelope transition binding
- The route must say how a live callback frame is allowed to mint, unlock, or consume a later settlement envelope.
- A healthy system does not let a callback frame authorize any arbitrary downstream envelope, and it does not let a downstream consumer infer envelope truth from callback liveness alone.
- The clean question is:
which committed frame is allowed to emit which committed settlement envelope, exactly once, at which stage boundary?
-
Single-use consumption and asset provenance
- Both the frame and the envelope should behave like single-use capability objects.
- A route is healthiest when each stage consumes the previous object once, emits the next object once, and keeps asset provenance attached to the route-local bucket that actually produced it.
Whatever balance is left afterwardorwhatever payer field arrived lateris not safe route accounting.
Three route-lifecycle promotions healthy routers should not collapse
1. A route shell is reachable at all
- A signed route blob, approved execution plan, parser-valid path, or live fallback router branch exists.
- That is only a reachability fact. It does not yet prove which exact callback frame or settlement envelope is live for the current stage.
- Reviews get into trouble when
the route existsquietly becomesany later callback or settlement object produced during this route probably belongs here.
2. One exact stage-local frame or envelope has become canonical route truth
- The protocol has opened one callback frame or emitted one settlement envelope for one concrete stage boundary.
- That is already much stronger than mere route-shell reachability, because the system is now saying
this exact provider / actor / target / payer / counterparty / payload meaning is the authoritative object for this stage. - But it still does not answer how much money-moving authority should remain attached to that object.
3. That canonical stage object still deserves live payer, counterparty, and payout authority
- A downstream consumer is now allowed to spend route-local funds, wallet approvals, resolver inventory, refund rights, or other payout buckets against the accepted frame or envelope.
- This deserves its own review boundary, especially during degraded routing or after stage drift, retries, partial fills, or compatibility shims.
- The dangerous collapse is
this route is in progressbecoming the same story asthis exact stage object may still spend from this exact bucket at ordinary authority right now.
What sound design looks like
-
One outer route, but distinct per-stage security objects
- The outer route is the approved execution plan.
- Each callback-capable stage still gets its own callback frame.
- Each downstream money-moving stage still gets its own settlement envelope.
-
The route commits transitions, not just endpoints
- A safe route does not merely commit
start asset -> end assetorpool list. - It commits who may call back, which stage that callback belongs to, and which later settlement object can be trusted if that stage succeeds.
- A safe route does not merely commit
-
Stage-local objects are written before external control leaves
- If a later callback or consumer needs actor, target, payer, or pool context, that context should be recorded in trusted local state before the external call, not reconstructed afterward from attacker-shaped bytes.
-
Frame closure should precede unrelated refunds and user-directed sends
- If a route emits refunds or user-facing transfers while the prior privileged frame is still open, the route has not actually separated its stages.
- This is the GMX-style warning: refund paths are stage transitions, not harmless UX extras.
-
Envelope consumers should re-derive what the route already committed
- Canonical pool, payer, token ordering, or resolver identity should be re-derived from committed route state wherever possible.
- Downstream consumers should not accept
syntactically plausibleas a substitute forroute-authenticated.
-
Fallback route continuity should emit smaller stage objects, not keep the old ones alive
- If only one emergency router branch, one manual completion path, or one operator-assisted settlement lane survives, the route should open narrower callback frames and narrower settlement envelopes for that mode on purpose.
This is the only route we still trust enough to keep operatingshould mean smaller provider scope, smaller payer scope, fewer counterparties, and smaller payout buckets than healthy-mode routing, not continuity at the old authority budget.
Useful positive design shapes
1. Outer route hash plus per-stage frame / envelope hashes
- Use one outer route commitment, then derive or store distinct hashes for each callback frame and settlement envelope the route may emit.
- The route approval object stays compact, but each later stage still proves which exact sub-object is live.
- This is safer than one monolithic blob whose meaning changes by convention as execution progresses.
2. Stage-indexed callback slots
- Instead of one ambient
inExecutionorinFlashLoanbit, use stage-indexed slots that bind provider, actor, target, selector meaning, and nonce. - A callback then proves it is consuming slot
route R / stage S / frame N, not merely that the router is busy.
3. Envelope derivation from committed route state, not callback bytes alone
- If a settlement consumer needs to know the pool, payer, token set, or route stage, it should re-derive those from trusted route state or a committed envelope hash.
- Callback bytes can carry claims, but they should not be the sole source of settlement truth.
4. Transition receipts between stages
- A healthy router can model stage changes as receipts: frame consumed, envelope emitted; envelope consumed, payout bucket updated.
- This makes it much harder for one stale frame to authorize a fresh downstream path or for one downstream consumer to trust a context blob from the wrong stage.
5. Route-local payout and payer buckets
- The route should track which funds belong to this exact execution plan and which payer or inventory bucket is authorized for each stage.
- That avoids both ambient-balance payout bugs and
attacker-supplied payer fieldbugs.
6. Degraded-mode route objects with narrower authority
- If routing degrades to one emergency helper, one operator-assisted completion path, or one surviving venue family, the protocol should commit distinct degraded-mode callback frames and settlement envelopes instead of reusing healthy-mode ones.
- Healthy degraded mode usually means fewer callable providers, fewer settlement counterparties, narrower payer / inventory semantics, and lower per-window payout budgets than ordinary routing.
- The important design move is not merely
keep one route alive; it iskeep only a consciously smaller route lifecycle alive while trust is weaker.
Design questions worth asking first
- What exact outer route object was approved, signed, or quoted?
- Which stages inside that route can hand control away and later resume?
- For each such stage, what exact callback frame is precommitted before control leaves?
- For each money-moving stage, what exact settlement envelope is the downstream consumer allowed to trust?
- What explicit rule lets one committed callback frame emit or consume one committed settlement envelope?
- Do refunds, self-calls, or compatibility shims accidentally keep one stage alive while another begins?
- When value finally moves, does payout come from route-local accounting or from ambient balances / attacker-shaped payer fields?
Red flags that usually mean the route commitment is underspecified
The route bytes were signedused as if that automatically pinned callback provider, actor, and target at every later stageThe router is currently executingused as if that proved which internal selector or target object a callback may resumeThe payer is encoded in calldataeven though no trusted state first committed that payer for this route stageThe callback came from a real poolused as if that automatically authenticated the downstream settlement envelopeThe route hash commits everythingeven though stage meaning changes under different parsers, suffix layouts, or legacy compatibility pathsWe settle from whatever balance remains in the router / resolverused as if route-local provenance still exists
Failure-prevention checklist
- Commit one outer route object plus explicit per-stage callback-frame and settlement-envelope objects before any external call, callback, or resolver handoff can ask later logic to trust ambient context.
- Bind stage transitions in trusted local state: a live callback frame should only be able to emit or consume the one settlement envelope that the route already committed for that stage boundary.
- Replace ambient
isExecuting,inSwap,inFlash, or genericroute hash existsassumptions with stage-indexed, single-use capabilities that bind provider, actor, target, payer, counterparty, and payload meaning. - Write actor identity, target object, payer bucket, canonical counterparty, and stage meaning before external control leaves; do not let callback bytes, route suffixes, or resolver calldata define those fields on return.
- Recompute canonical downstream counterparties from trusted route state wherever practical instead of accepting syntactically plausible pool, resolver, or market context as if it were route-authenticated.
- Keep parser version, envelope layout, and callback payload meaning explicit per stage, and fail closed on mixed-format, legacy, or partially decoded route context.
- Consume both frame and envelope objects exactly once, clear them on success and failure paths, and refuse late callbacks or second settlement attempts that cannot prove they belong to a fresh committed stage.
- Settle from route-local asset buckets, escrow buckets, or explicitly authorized payer sources rather than whatever balance, allowance, or resolver inventory happens to still be reachable.
- Pre-commit degraded-mode route policy too: if only one emergency router branch, one manual completion path, or one operator-assisted settlement lane remains live, automatically narrow provider scope, payer scope, counterparty set, and payout budget instead of preserving healthy-mode route authority by default.
- Treat refunds, compatibility shims, self-calls, and helper fast paths as real stage transitions that must either close the prior frame first or open a new committed object before value can move again.
- Fuzz and adversarially test stale-frame reuse, wrong-stage callbacks, parser drift, payer rebinding, counterfeit counterparties, degraded-mode route drift, and route-local bucket pollution as one joined end-to-end routing problem.
Audit prompts
- What exact outer route object was approved, and where are the per-stage callback-frame and settlement-envelope objects committed before any external call leaves the protocol?
- Which fields are re-derived from trusted local state versus re-decoded from callback bytes, appended suffixes, route calldata, or resolver payloads after the route is already in flight?
- Can a genuine callback from provider B inherit authority opened for provider A, or can one still-live stage authorize a different next stage than the route originally committed?
- What exact rule proves that frame
R/S/Fmay emit or consume envelopeR/S/E, and what fails closed if the callback arrives at the wrong stage, for the wrong actor, target, payer, or counterparty? - Do refunds, ETH sends, token sends, compatibility adapters, or internal self-calls happen while a privileged frame is still open, effectively creating an uncommitted stage transition?
- When downstream settlement spends funds, is it consuming a route-local authorized bucket or dipping into a broader allowance / balance / resolver inventory surface that the route only weakly constrains?
- Can parser-version drift, nested payloads, user-controlled offsets, or legacy route formats change which bytes later code interprets as callback meaning or settlement truth?
- What clears frame and envelope state on revert, retry, partial fill, or abandonment, and can stale route context survive long enough for a second callback or consumer to reuse it?
- If only one emergency router branch, one manual completion path, or one operator-assisted settlement lane survives during degraded operation, what exact provider scope, payer scope, counterparty set, and payout budget disappear automatically — and which ones dangerously survive just because the same route shell is still alive?
- If the callback source is genuine and the settlement bytes decode cleanly, what additional locally checkable proof still shows that actor, target, payer, counterparty, and stage meaning belong to the same route lifecycle?
- Which production telemetry would reveal route-commitment drift early: overlapping provider windows, unexpected stage transitions, parser fallbacks, wrong-pool callback attempts, payer substitutions, degraded-mode scope creep, or settlement spends outside route-local bounds?
Lessons that should already be standard
- One signed route blob is not the same thing as one authenticated route lifecycle. Healthy systems still need distinct stage-local objects for callback truth and settlement truth.
Real callbackandreal routerare necessary but incomplete claims. The decisive question is whether the same committed route stage still binds actor, target, payer, counterparty, payload meaning, and funds.- Stage transitions are security boundaries, not orchestration details. Refunds, self-calls, and compatibility paths become exploits when they inherit one stage’s authority while beginning another stage’s work.
- Callback liveness and settlement authenticity fail in different ways. Collapsing them into one ambient
route is executingstory guarantees that one drift will eventually be mistaken for the other. - Route-local provenance matters as much as route-local intent. If final settlement can draw from ambient balances, allowances, or resolver inventory, then even a correctly committed route can still pay from the wrong bucket.
- Parser and serializer choices are part of route security whenever they decide where stage meaning, payer identity, or downstream counterparty truth lives.
- Single-use consumption is not bookkeeping polish; it is what stops one stale frame or one stale envelope from becoming a reusable cross-stage capability.
Only live route leftis not the same thing asthis route still deserves ordinary authority. Weaker live workflow should imply smaller callback frames, smaller settlement envelopes, and smaller payout budgets, not continuity at the old route budget.- The cleanest routing designs can always answer one machine-checkable question:
which exact stage object is live right now, and which exact next object is it allowed to produce or consume?
Negative exemplar cluster: where route truth split at different joints
- f(x) Protocol, GMX V1, and Exactly Protocol preserve the callback-frame side of the problem: a route kept some execution path live, but the frame that should have bounded actor / target / stage authority was too ambient.
- 1inch Fusion V1 preserves the settlement-envelope side of the problem: the caller could still be the real router, but the protocol-authored settlement bytes the downstream resolver trusted were no longer the intended object.
- Primitive Finance, Sushi RouteProcessor2, and ParaSwap Augustus V6 preserve the mixed downstream-consumer side: the approval-funded settlement surface never had one fully pinned route-authenticated envelope for pool, payer, and callback meaning.
How to use this note with the exploit corpus
- Start here when the sharper design question is
how should a router, solver, or helper keep route truth pinned across both callback resumption and downstream settlement, without pretending they are the same security object? - Use callback frame truth as a single security object when the live bug is mostly about stale or overly broad in-flight authority.
- Use settlement envelope truth as a single security object when the live bug is mostly about the wrong protocol-authored settlement object being trusted downstream.
- Use this note when the design task is end-to-end: you need to explain how those two objects should stay connected across one route lifecycle.
- Pair with trusted execution-envelope corruption and callback-origin authentication failure when the negative side of the story matters more than the positive route-commitment design.
Internal linkages
- Callback-side companion: callback-frame-truth-security-object.
- Settlement-side companion: settlement-envelope-truth-security-object.
- Callback exploit family: reentrancy.
- Settlement exploit family: trusted-execution-envelope-corruption.
- Adjacent callback-authentication family: callback-origin-authentication-failure.
- Approval-funded router companion: approval-funded-route-authority-truth-security-object — use this when the sharper design question is not the whole route lifecycle, but the narrower allowance-backed route authority object that should have bounded which spender surface, payer, target set, and callback counterparty could ever spend from a wallet.
- Adjacent counterfeit-root-object family: account-confusion-root-of-trust-substitution.
- Best mixed exemplar cluster: f(x) Protocol, GMX V1, Exactly Protocol, 1inch Fusion V1, Primitive Finance, Sushi RouteProcessor2, ParaSwap Augustus V6.
Control surface
-
The decisive control surface is not just the route hash, solver quote, or callback caller.
-
It is the full route lifecycle: which stage is live, which callback frame that stage opened, which settlement envelope that stage is allowed to emit or consume, and which route-local funds or payer bucket the stage is actually allowed to spend.
-
In practice the dangerous collapse often has three steps: a route shell is still reachable, one stage-local frame or envelope gets promoted into canonical route truth, and that accepted stage object still inherits live payer / counterparty / payout authority at ordinary size.
-
Routing systems stay healthiest when they treat callback truth and settlement truth as two linked but distinct security objects, then commit and consume each one explicitly instead of collapsing both into one ambient
path is executingassumption. -
Sources:
- callback-frame-truth-security-object
- settlement-envelope-truth-security-object
- reentrancy
- trusted-execution-envelope-corruption
- fx-protocol-double-flash-loan-stale-callback-context-victim-position-drain-near-miss-2025-06-17
- gmx-v1-arbitrum-orderbook-refund-cross-contract-reentrancy-2025-07-09
- exactly-protocol-debtmanager-malicious-market-permit-account-rebinding-reentrancy-drain-2023-08-18
- 1inch-fusion-v1-settlement-yul-calldata-corruption-resolver-substitution-drain-2025-03-05
- primitive-finance-connectors-fake-option-flash-swap-callback-approval-drain-whitehack-2021-02-22
- sushiswap-routeprocessor2-fake-pool-callback-approval-drain-2023-04-09
- paraswap-augustus-v6-uniswapv3swapcallback-fake-pool-approval-drain-2024-03-20
-
Last reviewed: 2026-08-01 UTC