Bridge Canonical-Path Exclusivity and Stale Authoring-Surface Deauthorization

  • Name: bridge canonical-path exclusivity and stale authoring-surface deauthorization
  • Category: bridge reference / route-evolution design / legacy-surface retirement note / source-authenticity hardening companion
  • Summary: Bridges often fix or extend a route by adding a safer canonical path — a new native-asset intake function, a stricter router, a cleaner channel binding, a replacement wrapper, or a reviewed relay artifact. The recurring mistake is stopping there. If older generic paths, helper rails, refund flows, wrappers, or compatibility shims can still emit the same relay-authoritative artifact or reach the same downstream mint / release meaning on weaker terms, the bridge has not really upgraded its truth boundary; it has only created a safer sibling next to the old one. Healthy bridges treat new canonical path exists and old path can no longer speak with equivalent authority as the same security transition.
  • Why this note exists:

Three preserved failure shapes worth comparing

1. Shared artifact, weaker sibling path

  • Qubit is the clean same event, unequal custody semantics exemplar.
  • depositETH() was the path that actually enforced ETH receipt, but generic deposit() could still emit the same Deposit artifact for the ETH resource through a weaker route.
  • The healthy design question is not only did relayers know what Deposit meant? but why was more than one path still allowed to speak that meaning?
  • Primary-source anchor: Qubit’s own exploit report says the older deposit path was a function that should not be used after depositETH was newly developed, but it remained in the contract and still let the bridge emit deposit truth on weaker terms.

2. New canonical intake lane, stale generic lane retained equal authority

  • Meter Passport is the clean we built the safer lane but never made it exclusive exemplar.
  • depositETH() became the intended wrapped-native custody lane, but the older generic deposit route could still reach handler logic that recorded the same deposit truth without the same native-value proof.
  • The healthy design question is what exact review, code boundary, and emitted artifact made the older lane lose its right to author wrapped-native deposit truth?
  • Primary-source anchor: Meter’s own postmortem says the wrapped-native deposit method assumed a wrapped native token does not need to be burned or locked because it was already transferred by the earlier wrapping path. That assumption only held if the generic route had already lost authority to reach the same accounting branch.

3. Helper / refund flow retained inbound authority after route evolution

  • THORChain 2021-07-22 is the clean router-adjacent helper still spoke with fresh-inbound authority exemplar.
  • returnVaultAssets()-style and refund-adjacent logic could still produce a router artifact Bifrost treated as a real inbound deposit.
  • The healthy design question is which exact router-side functions were still members of the inbound-authoring set after helpers, refunds, and recovery paths existed?
  • Primary-source anchor: THORChain’s postmortem says the second exploit used an attack contract behind the router and that Bifrost did not fully account for how smart-contract event manipulation could counterfeit receipt of assets. That is exactly the stale-authoring-surface problem: the bridge was still listening to a broader speaker set than the canonical deposit lane.

These incidents differ in mechanics, but they preserve one shared lifecycle lesson: a bridge does not get credit for inventing a healthier path if the old or adjacent paths still retain equivalent economic speech rights.

The five joints a healthy exclusivity transition should keep fused

  1. One canonical semantic family, one canonical authoring path

    • For each relay-authoritative meaning — deposit, burn proof, refund, rollback, migration, release approval — the bridge should be able to name one canonical path or one deliberately tiny speaker set.
    • Several functions eventually do the same thing is exactly the state attackers monetize.
  2. Artifact exclusivity, not just implementation preference

    • It is not enough for developers to intend that one path is the right one.
    • The actual relay-visible artifact, deposit record, packet class, or message discriminant must become exclusive to that canonical path.
    • If the old path can still emit the same artifact, the old path is still live authority.
  3. Legacy and helper paths fail closed against canonical meanings

    • Refund, recovery, migration, compatibility, wrapper, and admin-helper flows should either use distinct non-authoritative artifact families or lose the ability to emit bridge-significant artifacts altogether.
    • This helper should never be used that way is not deauthorization.
  4. Route evolution updates both onchain and offchain policy

    • Upgrades to canonical lanes must propagate into relayer allowlists, guardian decoding, parser routing, alerting, and replay tooling.
    • If offchain observers still accept artifacts from the demoted path, the demotion is incomplete.
  5. Residual route authority is observable and removable

    • Operators should be able to answer which deprecated or non-canonical path could still author a live bridge fact today?
    • Healthy bridges make those residual rights enumerable, testable, and explicitly revocable.

Four demotion proofs a healthy bridge migration should be able to show

  1. Authoring-set proof

    • The team can enumerate every function, handler, channel, helper, wrapper, and parser path that used to be able to speak the semantic family in question.
    • Review should be able to point to the exact change that removed the deprecated member from that authoring set or narrowed it into a harmless local-status path.
    • Frontend now prefers the new route is not this proof.
  2. Artifact-family proof

    • The canonical path now emits a distinct relay-authoritative artifact family, or the deprecated path is mechanically incapable of emitting the old one.
    • If two paths still share one event, packet, or deposit-record format, the migration has to show the concrete guard that makes one of them non-authoritative for the route’s real economic meaning.
    • This is where Qubit and Meter both failed: the bridge had one healthier custody story in mind but never made the bridge-truth artifact exclusive to that story.
  3. Observer-policy proof

    • Offchain relayers, guardians, indexers, replay tools, dashboards, and alerting have been updated to reject or visibly distinguish the deprecated artifact source.
    • A demoted path that still looks normal in relayer intake or monitoring is still carrying operational authority even if the code comments say otherwise.
  4. Residual-reachability proof

    • Operators can still answer whether resource remaps, wrapper aliases, legacy channels, compatibility parsers, admin helpers, or refund paths could silently reactivate the demoted semantics.
    • This proof matters because bridge migrations often fail through the old route was gone in the main story, but one adjacent shim still resolved into the same downstream meaning.

A good migration review therefore asks four blunt questions: who can still speak?, what artifact can they still emit?, who still listens?, and what side door could make the old meaning live again?

What sound design looks like

  • Canonical path means exclusive path
    • Once a bridge decides this is the custody-valid native deposit lane or this is the only endpoint allowed to author mintable traffic, every weaker sibling path should either revert, emit a different non-authoritative artifact, or be unable to reach the same downstream accounting state.
  • Different semantics get different artifact families
    • Deposit, refund, return, migration, rollback, recovery, and maintenance flows should not share one relay-authoritative event, packet, or deposit-record format unless they truly share one economic meaning.
  • Legacy reachability is treated as bridge truth risk
    • A stale generic entrypoint, old wrapper, wrong channel, or helper rail that still reaches live bridge accounting is not a cleanup chore. It is an active bridge-authentication vulnerability.
  • Demotion is a state transition, not a comment
    • When the canonical route changes, the bridge should update code, config, relayer policy, monitoring, and incident runbooks together. Healthy teams can point to the commit or governance action that made the old path unable to publish equivalent truth.
  • Bridge-facing helper code is typed and local
    • Helper rails that must remain callable should emit clearly distinct local-status or recovery artifacts that cannot be mistaken for fresh deposits or release approvals.
  • Residual-authority review sits below incident response
    • Even before an exploit, operators should keep an inventory of deprecated routes, helper artifacts, compatibility shims, and parser exceptions that would become dangerous if a new canonical path were added tomorrow.

Failure-prevention checklist

  • For each bridge message family, name the one canonical path or one tightly bounded speaker set allowed to author it.
  • Make relay-authoritative artifacts exclusive to that path. If a path is not supposed to create fresh deposit or release truth, it should not be able to emit the same event schema, packet class, or persisted deposit record.
  • When introducing a safer route, explicitly deauthorize the weaker predecessor: revert the old entrypoint, sever its access to the same handler branch, or map it onto a distinct non-authoritative artifact family.
  • Ensure helper, refund, migration, recovery, and compatibility flows cannot accidentally inherit canonical deposit or inbound semantics through shared emitters, shared topics, or shared bookkeeping writes.
  • Update relayer, guardian, replay, and monitoring policy in the same change that narrows the onchain authoring surface. Offchain acceptance of stale artifacts is still stale authority.
  • Version or clearly separate artifact families when semantics change. If a safer route now means measured native custody happened first, the emitted event, packet, or stored record should either encode that stronger meaning directly or be unreachable from every weaker sibling path.
  • Keep a machine-readable authoring-surface inventory for each semantic family. Teams should be able to list canonical, transitional, deprecated, and helper-only speakers without reconstructing that set from folklore during an incident.
  • Keep preferred path and only path allowed to speak bridge truth as separate review fields. A route is not demoted until both fields collapse to the same answer.
  • Add tests that prove the demotion: legacy paths, helper paths, wrapper routes, and wrong-channel traffic should fail closed when they try to emit or register canonical bridge artifacts.
  • Treat parser compatibility, alias tables, resource remaps, and wrapper support as possible routes back into demoted semantics. Review them as residual-authority surfaces, not as convenience details.
  • Preserve route-local kill switches or denylist controls so if a supposedly demoted path is discovered still live, operators can isolate it without halting every healthier route.
  • Periodically inventory the whole source-authoring set and ask which members are canonical, transitional, deprecated, or accidentally still equivalent.

Audit prompts

  • What exact source-side functions, handlers, channels, wrappers, or helper rails can still emit the canonical relay-authoritative artifact for this asset or message family?
  • If the team says one route is canonical today, what concrete code or policy change made the predecessor incapable of authoring equivalent bridge truth?
  • Do any helper, refund, rollback, migration, or recovery flows still reach the same event schema, message discriminant, deposit record, or handler state as the canonical path?
  • When route evolution happened, were relayer and guardian allowlists narrowed too, or do offchain observers still accept artifacts from the older surface?
  • Did the migration change the artifact family itself, or does one legacy-looking event / packet still require reviewers to rely on code-path folklore to know whether it carried real bridge authority?
  • Can a stale path still become economically live through resource remaps, wrapper aliases, channel changes, or generic handlers that were not part of the main migration story?
  • If two paths share one event or packet shape, what mechanical check proves only one of them still carries mint or release authority?
  • Which deprecated routes remain callable only for backwards compatibility, and what prevents them from producing artifacts that downstream components could misread as canonical truth?
  • Does monitoring distinguish canonical-artifact emissions from legacy-path emissions, or would a stale-authority event blend into normal bridge traffic?
  • If a new safer path were introduced tomorrow, what template does the team already have for proving the old path lost equivalent authority instead of merely falling out of documentation?
  • What is the emergency lever if a demoted route turns out to have remained live: route-local pause, emitter denylist, parser blocklist, or only a full bridge shutdown?

Lessons that should already be standard

  • Safer sibling paths do not harden a bridge by themselves. Security improves only when weaker siblings lose equivalent authority.
  • A bridge artifact is part of the API surface of truth. If an old path can still emit the same artifact, that old path still matters no matter what the docs say.
  • Helper and refund flows are not harmless plumbing. Once offchain observers treat their output like fresh inbound or release authority, they are bridge-core security surfaces.
  • Migrations fail when they move the happy path but not the trust boundary. Users should use the new route is not the same claim as only the new route can publish money-good bridge facts.
  • Route evolution is a full-stack change. Onchain code, offchain relayers, parsers, dashboards, and incident controls all need the same narrowed authoring set.
  • Distinct semantics deserve distinct artifacts. Shared event or packet surfaces across deposit, refund, and maintenance flows routinely turn operational convenience into counterfeit bridge truth.
  • Residual authority is easiest to miss precisely when teams believe they already fixed the problem. The stale path gets less attention while retaining the same economic speech rights.
  • The healthy target is boringly exclusive: one semantic family, one canonical artifact, one narrow speaker set, and every non-canonical cousin visibly unable to say the same thing.
  • Route upgraded should come with evidence, not narrative. Healthy bridges can show the authoring-set diff, the artifact-family diff, the observer-policy diff, and the residual-reachability check that made the migration real.

Why this control matters

  • Bridges rarely fail only because the new path is weak. They often fail because the team already knew the healthier path, documented it, maybe even shipped it, but never removed equivalent authority from the older or adjacent path.
  • That makes route evolution a security event, not just a product update. A migration is incomplete until the predecessor path, helper rail, wrapper, or compatibility shim can no longer publish the same money-good artifact on cheaper terms.
  • This control matters because residual authority is socially invisible. Once docs, frontends, and operators all point to the safer path, the stale path gets less scrutiny precisely while it may still retain the same relay-authoritative speech rights.
  • It also matters offchain. Even if the onchain happy path moved, relayers, parsers, replay tooling, dashboards, and incident runbooks can keep the old trust boundary alive if they still accept the deprecated artifact family or emitter.
  • The practical review question is therefore lifecycle-shaped rather than code-shaped: after introducing a safer route, what exact mechanism made every weaker cousin unable to say the same economic thing anymore?

How to use this note with the exploit corpus

Internal linkages

Control surface