Einleitung
Zwischen dem 29.09.2026 und 01.10.2026 nutzte ein Angreifer die Verarbeitung von Rückerstattungen bei Einzahlungen in NEAR Intents aus, um interne Guthaben ohne entsprechende Deckung durch Vermögenswerte zu erzeugen. Durch sieben verifizierte Abhebungen aus dem HOT-Bridge-Vault auf BNB Chain wurden insgesamt 3.865.021 USDT transferiert. In seiner späteren Ursachenanalyse führte das Projekt den Fehler auf den NEAR-Intents-Contract zurück und erklärte, dass alle betroffenen Mittel am 2. Oktober zurückgegeben worden seien [1].
Um zu verstehen, wie der Rückerstattungsfehler ein abhebbares Guthaben erzeugte, muss man die Einzahlung durch den asynchronen Ausführungsablauf von NEAR verfolgen. Entwickler, die auf NEAR aufbauen, müssen berücksichtigen, wann Zustandsänderungen festgeschrieben werden, wer nachfolgende Schritte aufrufen kann und wie sich Fehler auf den Gesamtablauf auswirken. Audits müssen diese Wechselwirkungen über den gesamten Ablauf hinweg untersuchen.
Auf Grundlage unserer Erfahrung mit Audits von NEAR-Contracts und der Analyse von Sicherheitsvorfällen untersuchen wir anhand dieses Falls die Sicherheit der asynchronen Abwicklung auf NEAR. Zunächst erläutern wir die Grundlagen, die zum Verständnis des Exploits erforderlich sind: asynchrone Aufrufe und Receipts auf NEAR, Token-Transfers und Rückerstattungen sowie die Beziehung zwischen NEAR Intents und HOT Bridge. Anschließend erklärt die Vorfallanalyse die Schwachstelle und den Angriffsablauf, gefolgt von den Korrekturen und der Rückgewinnung der Mittel. Abschließend erörtern wir die Zustandsverwaltung und die Handhabung von Callbacks und gehen dann auf die Autorisierung von Konten und Speicherkosten ein.
Hintergrund
Die folgende Analyse stützt sich auf drei Besonderheiten von NEAR: die Ausführung asynchroner Contract-übergreifender Aufrufe, die Verarbeitung von Token-Transfers und Rückerstattungen nach NEP-141 und NEP-245 sowie die Deckung der von NEAR Intents erfassten internen Guthaben durch Vermögenswerte im HOT-Omni-Balance-Ledger.
Asynchrone Contract-übergreifende Aufrufe auf NEAR
Anders als bei Ethereum, wo Contract A Contract B synchron aufruft und auf dessen Rückgabe wartet [2], plant NEAR Contract-übergreifende Vorgänge zur späteren Ausführung ein. Der auslösende Aufruf, der externe Aufruf und der Callback teilen sich daher keinen gemeinsamen Ausführungskontext [3]. Zwei Begriffe sind für dieses Modell zentral:
-
Promise: Ein Vorgang, den ein Contract einplant, etwa den Aufruf eines anderen Contracts oder die anschließende Ausführung eines Callbacks.
-
Receipt: Eine Nachricht, mit der das Netzwerk Operationen ausführt und Ergebnisse zwischen Konten weitergibt. Ein Action Receipt führt eingeplante Operationen auf einem Zielkonto aus, während ein Data Receipt ein Ausführungsergebnis an ein davon abhängiges Action Receipt übermittelt [4].
Das folgende Diagramm zeigt diesen Ablauf aus Aufruf und Callback anhand von drei Action Receipts. In Receipt A aktualisiert Contract A seinen Zustand und erstellt eine Promise, um B aufzurufen. Receipt B führt die Logik von B aus. Ein im Diagramm nicht dargestelltes Data Receipt übermittelt das Ergebnis von B an Receipt C, wo es vom Callback von A verarbeitet wird. Receipt A kann abgeschlossen und sein Zustand festgeschrieben werden, bevor B oder der Callback ausgeführt wird.

Da diese Action Receipts unabhängig voneinander ausgeführt werden, kann der Contract während der Wartezeit andere Anfragen verarbeiten. Schlägt das Callback-Receipt fehl, werden die darin vorgenommenen Änderungen rückgängig gemacht; der durch das ursprüngliche Receipt festgeschriebene Zustand bleibt jedoch bestehen. Der Fehler kann sich nicht rückwärts ausbreiten und ihn rückgängig machen. Die Anwendung muss die Konsistenz daher ausdrücklich wiederherstellen.
Token-Standards und asynchrone Abwicklung von Rückerstattungen
NEP-141 und NEP-245 sind Token-Standards auf NEAR. NEP-141 umfasst fungible Token und ist grob mit ERC-20 auf Ethereum vergleichbar. NEP-245 umfasst mehrere Token-Typen und Batch-Operationen und ist grob mit ERC-1155 vergleichbar [5] [6] [7] [8].
Die Entsprechung ist nicht exakt. Bei einem normalen NEAR-Token-Transfer werden Vermögenswerte an die Zieladresse receiver_id gesendet, die ein Konto mit oder ohne Contract-Code bezeichnen kann. Bei den hier behandelten Transfer-and-Call-Abläufen ist der Empfänger ein Contract-Konto, das ft_on_transfer() für NEP-141 oder mt_on_transfer() für NEP-245 implementiert. Der Empfänger-Hook wird in einem Receipt ausgeführt; später führt der Token-Contract ft_resolve_transfer() oder mt_resolve_transfer() in einem anderen Receipt aus, um den verbrauchten Betrag und eine etwaige Rückerstattung abschließend festzulegen. Ein Ablauf, der von einer einzigen Nutzertransaktion ausgeht, kann sich somit über mehrere Receipts erstrecken.
Über seinen Hook meldet der Empfänger den Betrag, den er nicht verwendet hat. Dieser Rückgabewert dient als Eingabe für die Abwicklung und ist nicht zwangsläufig die endgültige Rückerstattung. In der Referenzimplementierung von NEP-141 in near-contract-standards begrenzt der Resolver den gemeldeten ungenutzten Betrag sowohl durch den ursprünglichen Transfer als auch durch das verfügbare Guthaben des Empfängers. Eine fehlgeschlagene oder ungültige Antwort wird zunächst als Aufforderung behandelt, den gesamten Transferbetrag zurückzuerstatten; anschließend gelten dieselben Begrenzungen [9]. Nach NEP-245 muss der Multi-Token-Resolver den Token-Transfer rückgängig machen, wenn die Promise-Kette fehlschlägt [8]. In beiden Fällen macht eine Rückerstattung auf Token-Ebene den Anwendungszustand, den der Empfänger in einem früheren Receipt festgeschrieben hat, nicht automatisch rückgängig.
NEAR Intents und HOT Bridge
NEAR Intents ist ein Intent-basiertes Abwicklungsprotokoll auf NEAR. Nutzer zahlen Vermögenswerte in intents.near ein, einen Contract, der sie als interne Guthaben erfasst. Anschließend können sie Intents signieren, um diese Guthaben zu tauschen oder abzuheben [10].
HOT Bridge, auch HOT Omni Bridge genannt, stellt die Cross-Chain-Vermögenswertschicht bereit. Vermögenswerte werden in Contracts auf externen Chains gesperrt, während entsprechende Omni-Assets im HOT-Omni-Balance-Contract auf NEAR geprägt werden. HOT Omni Balance implementiert das Token-Ledger nach NEP-245 [11].
Die Integration umfasst somit drei Buchführungsebenen: den auf der externen Chain gesperrten Vermögenswert, seine Repräsentation als Omni-Asset in HOT Omni Balance und das interne Guthaben des Nutzers in intents.near. Diese Ebenen müssen konsistent bleiben.
Das folgende Diagramm zeigt beispielhaft eine Einzahlung von 10 Einheiten und die beiden Zweige, nachdem Intents den Betrag dem internen Guthaben gutgeschrieben hat. Ohne Einzahlungsaktion gibt mt_on_transfer() ungenutzte Beträge von null zurück und ruft keinen Empfänger-Hook auf. Bei DepositAction::Notify ruft Intents den Empfänger auf und verwendet später mt_resolve_deposit(), um die interne Gutschrift anhand der Antwort des Empfängers anzupassen. Im Notify-Zweig verwendet der Empfänger 6 Einheiten und meldet 4 als ungenutzt. mt_resolve_transfer() von HOT Omni Balance erstattet diese 4 Einheiten zurück. Damit verbleiben 6 Einheiten im internen Guthaben des Nutzers und 6 Einheiten zusätzlicher Deckung im Ledger nach NEP-245 [12].

Vorfallanalyse
Wir untersuchen den Vorfall in drei Teilen: Die Schwachstellenanalyse erklärt, wie die Verarbeitung von Rückerstattungen interne Guthaben ohne Deckung durch Vermögenswerte hinterlassen konnte; die Angriffsanalyse verfolgt die Transaktionen und Receipts, mit denen dieses Verhalten ausgenutzt wurde; der Abschnitt zu Korrekturen und Rückgewinnung behandelt die vorgenommenen Änderungen und die gemeldete Rückgabe der Mittel.
Schwachstellenanalyse
Die folgende Quellcodeanalyse basiert auf der Revisionsfassung 35044fd, mit der das Projekt den Vorfall reproduzierte [13]. Eine unzureichende Validierung der Rückerstattung konnte ein übergroßes Rückerstattungsereignis erzeugen, sodass der Callback fehlschlug und interne Guthaben nicht mehr mit den gehaltenen Vermögenswerten übereinstimmten:
-
Unzureichende Validierung des Rückerstattungsbetrags. Der betroffene Einzahlungspfad in
intents.nearbegrenzte die Rückerstattung anhand des Guthabens und der Anforderung des Empfängers, berücksichtigte aber nicht den Betrag, der bei dem abzuwickelnden Transfer eingezahlt worden war. Ein hohes bereits vorhandenes Guthaben konnte folglich eine Rückerstattung ermöglichen, die weit über der aktuellen Einzahlung lag.
-
Übergroßes Rückerstattungsereignis. Ein Batch mit langen Token-Kennungen und hohen Rückerstattungswerten konnte ein serialisiertes
MtBurnEventerzeugen, das die Log-Größenbegrenzung überschritt. Die Ausgabe dieses Ereignisses mittelsemit()konnte den Rückerstattungs-Callback abbrechen [14]. Die Begrenzung gilt für die Ereignisnutzlast einschließlich ihrer Arrays und Formatierung; ein hoher numerischer Rückerstattungsbetrag allein belegt nicht, dass das Ereignis die Begrenzung überschreitet.
Das Einzahlungsereignis verwendet die transferierten Beträge, sodass kleine Einträge dieses Ereignis innerhalb der Begrenzung halten können. Das spätere Rückerstattungsereignis verwendet die vom Resolver akzeptierten Beträge. Ohne Begrenzung auf den eingezahlten Betrag kann die Prüfung des ursprünglichen Ereignisses nicht sicherstellen, dass das größere Rückerstattungsereignis innerhalb der Begrenzung bleibt.
-
Inkonsistente Abwicklung der Rückerstattung. Der Callback
mt_resolve_deposit()von Intents zog interne Guthaben und die Menge der ausgegebenen Token innerhalb seines eigenen Receipts ab. Führte die Ausgabe des Rückerstattungsereignisses dazu, dass dieses Receipt fehlschlug, wurden diese Abzüge rückgängig gemacht, während die im früheren Einzahlungs-Receipt festgeschriebene Gutschrift bestehen blieb. Der vorgelagerte Token-Contract konnte daraufhin die transferierten Vermögenswerte zurückerstatten, sodass die bestehen gebliebene interne Gutschrift nicht mehr durch entsprechende Vermögenswerte gedeckt war. Durch Wiederholung dieses Vorgangs konnte das ungedeckte interne Guthaben weiter aufgebläht werden.
Bester Sicherheitsauditor für Web3
Prüfen Sie Design, Code und Geschäftslogik vor dem Start
Angriffsanalyse
Der Angreifer nutzte ein Token, um das Rückerstattungsereignis aufzufüllen (das „Füll-Token“), sowie einen bösartigen Empfänger, um übergroße Rückerstattungsanforderungen auszulösen. Dadurch blähte er wiederholt interne Guthaben ohne entsprechende Deckung durch Vermögenswerte auf. Das Projekt meldet insgesamt 23 fehlgeschlagene Einzahlungstransaktionen [1]. Durch sieben verifizierte Abhebungen wurden 3.865.021 USDT aus dem HOT-Bridge-Vault auf BNB Chain transferiert.
Der Angriff umfasste mehrere Transaktionen. Diese Analyse konzentriert sich auf 13 zentrale Transaktionen, die in Anhang A aufgeführt sind, und ordnet sie drei funktionalen Phasen zu.
-
Phase 1: Vorbereitung (Tx 1–4). Der Angreifer beschaffte die für Tests benötigten Vermögenswerte, stellte den bösartigen Empfängervertrag bereit und stattete dessen internes Guthaben an Füll-Token vorab aus.
-
Phase 2: Erhöhung des Guthabens (Tx 5–6). Tx 5 und Tx 6 sind die erste bzw. letzte identifizierte Transaktion zur Erhöhung des Guthabens.
-
Phase 3: Auszahlungen auf BNB Chain (Tx 7–13). Der Angreifer nutzte die aufgeblähten internen Guthaben, um
USDTaus dem Vault von HOT Bridge auf BNB Chain abzuheben.
Diese Phasen ordnen die Handlungen des Angreifers ein; sie sind keine drei zeitlich überschneidungsfreien Abschnitte. Aktivitäten zur Erhöhung des Guthabens und Auszahlungen überschnitten sich. Die folgende detaillierte Rekonstruktion untersucht Tx 5 und die Ergebnisse aller zugehörigen Action-Receipts und prüft anschließend die sieben Auszahlungen auf BNB Chain.
Beim ersten Beispiel für die Erhöhung des Guthabens kam der hier gezeigte bösartige Empfänger zum Einsatz; spätere Transaktionen verwendeten andere bösartige Empfängerkonten. Vollständige Adressen und Token-IDs sind in Anhang B aufgeführt. Alle folgenden Uhrzeiten sind in UTC angegeben.
| Im Folgenden verwendete Bezeichnung | Rolle | Chain |
|---|---|---|
| Angreifer | Vom Angreifer kontrollierter Transaktionsabsender | NEAR |
| Bösartiger Empfänger | Vertrag für Benachrichtigungs-Callbacks / Inhaber des internen Guthabens | NEAR |
| Füll-Token | Vom Angreifer bereitgestellter Token zum Auffüllen des Batches | NEAR |
USDT-Repräsentation |
Auf NEAR repräsentierter Vermögenswert von BNB Chain | NEAR |
USDT |
Zugrunde liegender Token | BNB Chain |
| Intents | Vertrag für die interne Abwicklung | NEAR |
| HOT Omni Balance | Token-Ledger nach NEP-245 | NEAR |
| BNB-Empfänger | Vom Angreifer kontrollierter Auszahlungsempfänger | BNB Chain |
| HOT Bridge-Vault | Chainübergreifender Vault für Vermögenswerte | BNB Chain |
Phase 1: Vorbereitung (Tx 1–4)
-
Schritt 1 (Tx 1): Am 29. September um 12:30:44 erhielt der Angreifer über HOT Bridge
10e18Roheinheiten der BNB-Chain-USDT-Repräsentation, die seinem Konto in HOT Omni Balance gutgeschrieben wurden. Das Suffix der Token-ID lässt sich zur BNB-Chain-Adresse vonUSDTin Anhang B dekodieren. Bei 18 Dezimalstellen entsprechen10e18Roheinheiten 10USDT. -
Schritt 2 (Tx 2): Der Angreifer erhielt über HOT Bridge
97e36 + 97Roheinheiten des Füll-Tokens. Der eigens erstellte Token war zuvor am selben Tag auf Osmosis erstellt und geprägt worden. Danach wurde er über Kava und Gonka übertragen, bevor er auf NEAR beansprucht wurde; die Vorbereitungsschritte sind in Anhang C dokumentiert. -
Schritt 3 (Tx 3): Der Angreifer stellte den bösartigen Empfängervertrag bereit und initialisierte ihn.
-
Schritt 4 (Tx 4): Der Angreifer übertrug über
mt_transfer_call()von HOT Omni Balance97e36Roheinheiten des Füll-Tokens an Intents;msgbezeichnete dabei den bösartigen Empfänger. Intents schrieb den Betrag dem internen Konto des bösartigen Empfängers gut. Dieses vorab ausgestattete Guthaben ermöglichte es dem bösartigen Empfänger, während Tx 5 97 Rückerstattungsanforderungen über jeweils1e36Roheinheiten zu decken.
Phase 2: Erhöhung des Guthabens (Tx 5–6)
Die erste Transaktion zur Erhöhung des Guthabens, Tx 5, wurde am 29. September um 16:14:19 ausgeführt. Ihre fünf zentralen Action-Receipts umfassen die Batch-Übertragung, die Einzahlung, die Benachrichtigung, die fehlgeschlagene Buchungsanpassung und die vorgelagerte Rückerstattung. Ihre Kennungen und Ausführungsergebnisse sind in Anhang D aufgeführt.
-
Schritt 5 (Tx 5): Der Angreifer rief
mt_batch_transfer_call()auf HOT Omni Balance mit Intents als Ziel auf. Der Batch enthielt 97 Einträge für denselben Füll-Token mit jeweils 1 Roheinheit sowie einenUSDT-Eintrag über10e18Roheinheiten.mt_on_transfer()von Intents verbuchte alle 98 Einträge für den bösartigen Empfänger und gab einMtMint-Einzahlungsereignis aus. Der Betrag von 1 für jeden Füll-Eintrag war bewusst gewählt: Der Einzahlungspfad riefcheck_refund()auf, um zu prüfen, ob das ursprüngliche Ereignis einschließlich des erwarteten Aufwands für die Rückerstattung innerhalb des Log-Limits blieb. Kleine Einzahlungsbeträge bestanden diese Prüfung, während die späteren, wesentlich höheren Rückerstattungsanforderungen des bösartigen Empfängers ein zu großes Rückerstattungsereignis erzeugten [13].
-
Schritt 6 (Tx 5): Nach der internen Gutschrift nahm Intents den
DepositAction::Notify-Zweig und riefmt_on_transfer()des bösartigen Empfängers einmal mit allen 98 Einträgen auf. Der Aufruf beim bösartigen Empfänger war erfolgreich; er gab 97 Rückerstattungsanforderungen über jeweils1e36Roheinheiten für die Füll-Einträge und eine Rückerstattungsanforderung über 0 für denUSDT-Eintrag zurück. -
Schritt 7 (Tx 5):
mt_resolve_deposit()von Intents akzeptierte alle 97 Rückerstattungsanforderungen über jeweils1e36Roheinheiten, weil das in Tx 4 vorab ausgestattete interne Füll-Token-Guthaben des bösartigen Empfängers ausreichte, um sie zu decken. Diese hohen Rückerstattungswerte vergrößerten zusammen mit der wiederholten langen Token-Kennung dasMtBurnEvent-Log auf 16,495 Byte und überschritten damit das Limit von 16.384 Byte. Die Ausgabe des Ereignisses schlug fehl. Dadurch wurden die in diesem Receipt versuchten Guthabenabzüge zurückgenommen, während die frühere Einzahlungsgutschrift bestehen blieb.
-
Schritt 8 (Tx 5):
mt_resolve_transfer()von HOT Omni Balance erhielt vonmt_resolve_deposit()von Intents ein fehlgeschlagenes Promise-Ergebnis. Daher erstattete HOT Omni Balance dem Angreifer alle 98 Einträge in ihrer ursprünglich übertragenen Höhe zurück, einschließlich 10USDT, obwohl der bösartige Empfänger eine Rückerstattung von nullUSDTangefordert hatte. Der Angreifer erhielt die Vermögenswerte zurück, während dem bösartigen Empfänger die entsprechende interne Gutschrift in Intents erhalten blieb.
Der Angreifer wiederholte diesen Vorgang, um die internen Guthaben weiter zu erhöhen. Tx 6 verwendete einen anderen bösartigen Empfänger und löste denselben Fehler wegen Überschreitung der Log-Länge aus.
Phase 3: Auszahlungen auf BNB Chain (Tx 7–13)
- Schritt 9 (Tx 7–13): Der Angreifer nutzte das aufgeblähte interne Guthaben, um Auszahlungen über HOT Bridge anzufordern. Auf BNB Chain übertrugen die sieben als Tx 7–13 in Anhang A aufgeführten Transaktionen
USDTaus dem HOT Bridge-Vault an den vom Angreifer kontrollierten BNB-Empfänger.
Die ersten beiden kleinen Auszahlungen belaufen sich zusammen auf 21 USDT. Die folgenden fünf belaufen sich zusammen auf 3.865.000 USDT, woraus sich 3.865.021 USDT über alle sieben Transaktionen ergeben. Diese Beträge stammen aus den Transfer-Logs des Tokens und beruhen auf seiner Genauigkeit von 18 Dezimalstellen. Die Zeitstempel auf BNB Chain beziehen sich auf Übertragungen auf der Ziel-Chain und sind von den Zeitstempeln für Einzahlungen oder Auszahlungsanforderungen auf NEAR zu unterscheiden.
Korrekturen und Rückerlangung der Mittel
Das Team berichtet, dass am 2. Oktober eine Korrektur bereitgestellt wurde [1]. Die korrigierte Berechnung begrenzt jede Rückerstattung auf den Betrag, der bei der aktuellen Übertragung eingezahlt wurde. Die Grenzen durch den angeforderten Betrag und das verfügbare interne Guthaben bleiben dabei bestehen [15]:
let refund_amount = requested_refund.min(*deposited).min(balance_left);
Damit kann ein hohes Guthaben aus früheren Einzahlungen keine überhöhte Rückerstattung für eine spätere, kleinere Einzahlung mehr decken.
Anschließend entfernte das Team am 7. Oktober die Einzahlungsbenachrichtigungen [1] und schloss damit den Weg, über den ein bösartiger Empfänger Rückerstattungsanforderungen übermitteln konnte. PR #374 dokumentiert diese Entfernung [16]. Der Postmortem-Bericht nennt außerdem eine zusätzliche Schutzmaßnahme: Eine Überwachung vergleicht nun die gesamten internen Nutzerguthaben mit den tatsächlich vom Vertrag gehaltenen Token und pausiert den Vertrag automatisch, wenn die Werte voneinander abweichen [1].
Zur Rückerlangung der Mittel gab das Projekt am 2. Oktober bekannt, dass sämtliche Mittel zurückgegeben worden seien [17]. Der spätere Postmortem-Bericht bestätigte, dass alle betroffenen Nutzer vollständig entschädigt worden waren [1].
Sicherheitsaspekte für Smart Contracts auf NEAR
Der Vorfall bietet einen Ausgangspunkt, um die Zustandskonsistenz über asynchrone Receipts auf NEAR hinweg zu untersuchen. Aufbauend auf dieser Analyse und unserer Erfahrung mit NEAR-Audits behandelt dieser Abschnitt drei Bereiche: asynchrone Ausführung, Kontoautorisierung mittels Zugriffsschlüsseln und Speicherkosten. Die beiden letztgenannten Bereiche erweitern die Betrachtung darauf, wie Anwendungen Befugnisse delegieren und dauerhaften Zustand finanzieren. Im Mittelpunkt stehen Risiken, die durch diese Mechanismen von NEAR geprägt sind, sowie die konkreten Prüfungen, die sie bei Entwicklung und Audits erfordern. Allgemeine Sicherheitspraktiken werden dort einbezogen, wo sie zum Verständnis oder zur Bewältigung dieser Risiken beitragen.

Asynchrone Ausführung
1. Zustandsverwaltung über mehrere Receipts hinweg
Auf NEAR werden vertragsübergreifende Aufrufe und ihre Callbacks in separaten Receipts ausgeführt. Ein späterer Fehler macht einen zuvor festgeschriebenen Zustand nicht automatisch rückgängig. Verträge können zudem weitere Anfragen verarbeiten, während Aufrufe noch ausstehen. Deshalb sind der Zeitpunkt und die Isolation von Zustandsänderungen entscheidend, um interne Guthaben mit den tatsächlichen Vermögenswerten in Einklang zu halten. Drei häufige Szenarien verdeutlichen diese Risiken:
-
Verzögerter Guthabenabzug: Wenn das verfügbare Guthaben erst beim Callback abgezogen oder reserviert wird, können dieselben Mittel vor Abschluss der Übertragung erneut verwendet werden.
-
Vorzeitige Einzahlungsgutschrift: Werden verfügbare Mittel gutgeschrieben, bevor die externe Verarbeitung abgeschlossen ist, entstehen zwei Risiken:
- Verwendung vor der Abwicklung: Nutzer können die gutgeschriebenen Mittel verwenden, während der externe Aufruf noch aussteht und bevor die Abwicklung abgeschlossen ist.
- Fortbestehende Gutschrift nach einem Callback-Fehler: Schlägt der Rückerstattungs-Callback fehl, kann der vorgelagerte Token-Vertrag die Vermögenswerte zurückgeben, während die zuvor festgeschriebene interne Gutschrift bestehen bleibt. Der Vorfall bei NEAR Intents verdeutlichte dieses Risiko.
-
Überschreiben gemeinsam genutzten Zustands: Wenn ausstehende Anfragen dieselbe Variable für den Nutzer oder den Betrag verwenden, kann eine spätere Anfrage Informationen überschreiben, die der Callback einer früheren Anfrage benötigt. Eine Rückerstattung kann dann dem falschen Nutzer oder Betrag zugeordnet werden.
Empfehlungen. Da vertragsübergreifende Abläufe auf NEAR nicht über mehrere Receipts hinweg atomar sind, müssen bei Entwicklung und Auditierung der Zeitpunkt von Saldoaktualisierungen, die Trennung ausstehender Anfragen und die Wiederherstellung nach fehlgeschlagenen Aufrufen und Callbacks berücksichtigt werden. Ziehen Sie Mittel vor dem Einleiten von Auszahlungen ab oder reservieren Sie sie, und stellen Sie den Saldo nur einmal wieder her, falls die Übertragung fehlschlägt. Verhindern Sie bei Einzahlungen, dass Nutzer Mittel ausgeben, bevor die Abwicklung abgeschlossen ist, und stellen Sie sicher, dass erstattete Vermögenswerte kein ausgebbares internes Guthaben zurücklassen – auch dann nicht, wenn der Callback für die Abwicklung selbst fehlschlägt. Erfassen Sie für jede ausstehende Anfrage Nutzer, Betrag und Abwicklungsstatus getrennt. Überprüfen Sie dieses Verhalten bei erfolgreichen und fehlgeschlagenen Aufrufen, fehlgeschlagenen Callbacks, ineinander verschachtelten Anfragen und wiederholten Abwicklungsversuchen.
2. Callbacks bei vertragsübergreifenden Aufrufen
NEAR-Contracts verwenden Promises, um vertragsübergreifende Aufrufe und Callbacks zur Verarbeitung ihrer Ergebnisse zu planen. Der Zugriff auf Callbacks und die Behandlung von Fehlern bestimmen, ob die anschließende Buchführung oder Abwicklung wie vorgesehen erfolgt. Daraus ergeben sich zwei Risiken:
-
Uneingeschränkter Callback-Zugriff: Ein Callback muss als aufrufbare Contract-Methode verfügbar sein. Dadurch können ihn jedoch auch externe Aufrufer erreichen, sofern der Zugriff nicht eingeschränkt ist. Ein Angreifer kann einen ungeschützten Callback mit erfundenen Parametern aufrufen und so Buchführungs- oder Abwicklungslogik auslösen, ohne dass die vorgesehene vorherige Operation stattgefunden hat.
-
Fehlgeschlagene Callbacks: NEAR-Contracts verwenden
.then(), um Callbacks anzuhängen, die die Ergebnisse vertragsübergreifender Aufrufe verarbeiten und die erforderliche Abschluss- oder Wiederherstellungslogik ausführen. Schlägt der Callback selbst fehl, werden seine eigenen Zustandsänderungen rückgängig gemacht. Frühere erfolgreiche Receipts bleiben jedoch dauerhaft wirksam, was zu inkonsistenten Abwicklungszuständen führt.
Empfehlungen. Beschränken Sie den Zugriff auf Callbacks mithilfe von #[private] auf den Contract selbst [18]. Stellen Sie ausreichend Gas für den Callback bereit und begrenzen Sie den Arbeitsaufwand und die Menge der Log-Ausgaben, die er erzeugen kann. Behandeln Sie fehlgeschlagene Promise-Ergebnisse und fehlerhafte Rückgabedaten ausdrücklich. Da ein fehlgeschlagener Callback seine eigenen Wiederherstellungsänderungen nicht dauerhaft speichern kann, erfassen Sie den für die Wiederherstellung benötigten ausstehenden Abwicklungsstatus in einem früheren Receipt. Überprüfen Sie, dass ein fehlgeschlagener Callback kein ungedecktes, ausgebbares Guthaben zurücklässt und dass die Wiederherstellung dieselbe Operation nicht zweimal abwickeln kann.
Kontoautorisierung
NEAR ermöglicht eine differenzierte Kontoautorisierung durch zwei Arten von Zugriffsschlüsseln [19]: Function-Call- und Full Access-Schlüssel.
Wenn ein Nutzer eine Website mit einem Function-Call-Schlüssel autorisiert, kann die Website zulässige Methoden beim zulässigen Empfänger aufrufen, ohne für jede Operation eine neue Wallet-Signatur einzuholen. Die Laufzeitumgebung setzt diese Beschränkung durch und weist Aufrufe mit einer angehängten Einzahlung ungleich null für diesen Schlüsseltyp zurück [20].
Innerhalb dieses Berechtigungsumfangs lässt die Kontoidentität nicht erkennen, ob eine Operation mit dem delegierten Schlüssel signiert oder vom Nutzer einzeln genehmigt wurde. Eine sensible Methode, die sich allein auf diese Identität stützt, kann einer bösartigen Website ermöglichen, Übertragungen, Auszahlungen oder Berechtigungsänderungen einzuleiten, wenn diese Methoden von der Autorisierung umfasst sind.
Empfehlungen. Prüfen Sie, welche sensiblen Methoden über eingeschränkt berechtigte Schlüssel erreichbar sind und welche Autorisierung für die jeweilige Operation erforderlich ist. Die Anforderung, mit #[payable] und assert_one_yocto() genau 1 yoctoNEAR zu verlangen, schließt den direkten Transaktionsweg des eingeschränkt berechtigten Schlüssels aus. Behalten Sie die anwendungseigenen Identitäts- und Berechtigungsprüfungen bei: Die Einzahlungsanforderung beweist nicht, dass ein Mensch die Operation eingeleitet hat, denn Software kann einen Full Access-Schlüssel besitzen und ein anderer Contract kann NEAR anhängen.
Speicherkosten
NEAR verlangt, dass ein Contract NEAR für seine gespeicherten Daten reserviert. Ein wachsender Zustand verringert daher die für andere Operationen verfügbaren Mittel [21]. Die Risiken hängen davon ab, wer für dieses Wachstum zahlt:
-
Protokollfinanzierter Speicher: Wenn Nutzer Datensätze erstellen können, ohne dafür zu zahlen, und das Wachstum unbegrenzt ist, können wiederholte kostengünstige Aufrufe die Speicherverpflichtung des Contracts erhöhen und seine verfügbaren Mittel aufbrauchen.
-
Nutzerfinanzierter Speicher: Werden Nutzern Gebühren berechnet, müssen diese die Kosten vollständig decken und auf einer genauen Messung beruhen:
- Umgehung von Gebühren: Ein alternativer Einstiegspunkt kann Datensätze erstellen, ohne die auf dem üblichen Registrierungs- oder Schreibweg erforderliche Gebühr einzuziehen.
- Falsche Zuordnung der Nutzung:
env::storage_usage()misst den Speicherverbrauch des gesamten Contracts. Wird vor einem externen Aufruf ein Ausgangswert gespeichert und in einem späteren Receipt mit dem aktuellen Wert verglichen, können darin nicht zugehörige Schreib- oder Löschvorgänge enthalten sein. Dadurch kann die berechnete Gebühr die eigene Speicheränderung des Nutzers über- oder unterschätzen.
Empfehlungen. Speicherfinanzierung, Abdeckung der Schreibwege und Zuordnung der Nutzung müssen gemeinsam betrachtet werden. Erheben Sie Gebühren für neuen Speicher oder begrenzen Sie die Subvention und Kapazität des Protokolls ausdrücklich. Prüfen Sie jeden Schreibweg auf Möglichkeiten zur Umgehung von Gebühren. Messen Sie die Speicheränderung einer Operation nach Möglichkeit innerhalb desselben Receipts. Wenn sich die Buchführung über mehrere Receipts erstreckt, trennen Sie nicht zugehörige Änderungen ab, bevor Sie die Nutzung einem einzelnen Nutzer zuordnen.
Fazit
Auf NEAR kann ein erfolgreiches Receipt einen dauerhaften Zustand hinterlassen, selbst wenn ein späterer Callback fehlschlägt. Anders als bei einer synchronen Aufrufkette auf Ethereum gibt es für den Ablauf über mehrere Receipts hinweg keine gemeinsame Grenze für das Rückgängigmachen von Änderungen. Anwendungen müssen daher berücksichtigen, welche Zustände und Vermögenswerte nach jedem möglichen Fehler verbleiben.
Bei NEAR Intents wurde die Token-Erstattung abgeschlossen, während das entsprechende interne Guthaben eine fehlgeschlagene Buchführungsanpassung überstand. Eine unzureichende Validierung der Erstattung führte dazu, dass der Erstattungsbetrag groß genug war, um diesen Fehler auszulösen. Der Fall zeigt, dass die Rückgabe von Vermögenswerten auf Token-Ebene dennoch ein ungedecktes, ausgebbares Guthaben in einer Anwendung zurücklassen kann.
Bei ähnlichen asynchronen Abläufen sollten Entwicklung und Auditierung nachverfolgen, welche Zustandsänderungen jeden möglichen Fehler überstehen, ob ausstehende Guthaben ausgegeben werden können und wie unvollständige Abwicklungen ohne doppelte Gutschriften oder Erstattungen wiederhergestellt werden können. Jedes Receipt muss zusammen mit dem früheren Zustand, von dem es abhängt, und den späteren Operationen, die es plant, untersucht werden.
Über die Abwicklung hinaus verdienen auch die Berechtigungen von Zugriffsschlüsseln und die Speicherfinanzierung eine ausdrückliche Prüfung: Delegierte Aufrufe müssen innerhalb der vorgesehenen Befugnisse bleiben, und für nutzergetriebenes Zustandswachstum muss ein Kostenträger oder eine Grenze festgelegt sein.
Quellen
[1] NEAR Intents: Nachbericht vom 16.10.2026
[2] Ethereum.org: Sicherheit von Smart Contracts
[3] NEAR-Dokumentation: Vertragsübergreifende Aufrufe
[4] NEAR RuntimeSpec: Receipts
[6] ERC-1155: Multi-Token-Standard
[7] NEP-141: Standard für fungible Token
[8] NEP-245: Multi-Token-Standard
[9] NEAR SDK: Implementierung fungibler Token
[10] NEAR-Dokumentation: Integration mit NEAR Intents
[11] HOT Bridge-Architektur und HOT Omni Balance
[12] NEP-245-Einzahlungsablauf, Revision 35044fd zur Reproduktion
[13] Einzahlungs-Resolver, Revision 35044fd zur Reproduktion
[14] Regressionstest für überhöhte Erstattungen, zusammengeführte Revision 0c1a530
[15] Grenzen für Erstattungen im aktuellen Intents-Quellcode, abgerufen am 26.10.2026
[16] PR #374: Benachrichtigungen bei Einzahlungen entfernen
[17] NEAR Intents: Erklärung zur Wiederherstellung vom 02.10.2026
[18] NEAR-Dokumentation: Private Callbacks
[19] NEAR-Dokumentation: Zugriffsschlüssel
[20] NEAR RuntimeSpec: Validierung von Function-Call-Zugriffsschlüsseln
[21] NEAR-Dokumentation: Angriffe über Speicherkosten
Anhang
A. Zeitlicher Ablauf der Transaktionen {#appendix-verified-transaction-timeline}
Dieser Anhang behält die in der ursprünglichen Untersuchung verwendete Transaktionsnummerierung bei. Er führt die vier vorbereitenden Transaktionen, die erste und die letzte identifizierte Transaktion zur Saldoerhöhung sowie die sieben Auszahlungen auf BNB Chain auf. Er enthält keine vollständige Liste aller vom Projekt gemeldeten 23 fehlgeschlagenen Einzahlungstransaktionen. Alle Uhrzeiten sind in UTC angegeben; die Phasen klassifizieren Handlungen und können sich zeitlich überschneiden.
| Tx | Phase | Chain | Zeit (UTC) | Aktion | Transaktion |
|---|---|---|---|---|---|
| 1 | Vorbereitung | NEAR | 2026-09-29 12:30:44 | Repräsentation von 10 USDT beschaffen |
9SiSBvDe... |
| 2 | Vorbereitung | NEAR | 2026-09-29 16:09:34 | Füll-Token beschaffen | FmwaoRND... |
| 3 | Vorbereitung | NEAR | 2026-09-29 16:11:48 | Bösartigen Empfänger bereitstellen und initialisieren | GgbwMV8N... |
| 4 | Vorbereitung | NEAR | 2026-09-29 16:12:40 | Internes Füll-Token-Guthaben des bösartigen Empfängers vorfinanzieren | 4wf2FWcE... |
| 5 | Saldoerhöhung | NEAR | 2026-09-29 16:14:19 | Erste identifizierte Transaktion zur Saldoerhöhung | 3k91uDpU... |
| 6 | Saldoerhöhung | NEAR | 2026-10-01 05:47:27 | Letzte identifizierte Transaktion zur Saldoerhöhung | GAQKwHdT... |
| 7 | Cross-Chain-Auszahlung | BNB Chain | 2026-09-30 18:57:07 | 10 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x4f426e23... |
| 8 | Cross-Chain-Auszahlung | BNB Chain | 2026-09-30 20:05:24 | 11 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0xc002bd17... |
| 9 | Cross-Chain-Auszahlung | BNB Chain | 2026-09-30 23:54:30 | 800.000 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x9fe58e03... |
| 10 | Cross-Chain-Auszahlung | BNB Chain | 2026-10-01 00:24:02 | 1.200.000 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x0381265d... |
| 11 | Cross-Chain-Auszahlung | BNB Chain | 2026-10-01 00:50:42 | 1.500.000 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x69d1c68c... |
| 12 | Cross-Chain-Auszahlung | BNB Chain | 2026-10-01 01:46:20 | 330.000 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x9c10b967... |
| 13 | Cross-Chain-Auszahlung | BNB Chain | 2026-10-01 06:08:26 | 35.000 USDT aus dem HOT Bridge-Vault an BNB-Empfänger übertragen |
0x16ddfa69... |
B. Konten und Token-Identifikatoren {#appendix-accounts-and-token-identifiers}
Die ursprüngliche Untersuchung ordnet dem Angreifer beide unten aufgeführten Cross-Chain-Adressen zu. Die Blockchain-Daten belegen unabhängig davon ihre Rollen als Absender auf NEAR und als Empfänger der Auszahlung auf BNB Chain. Der hier aufgeführte bösartige Empfänger ist das in Tx 5 verwendete Konto; bei späteren Transaktionen zur Verstärkung des Angriffs wurden andere bösartige Empfängerkonten verwendet.
| Nachfolgend verwendete Bezeichnung | Rolle | Chain | Konto / Identifikator |
|---|---|---|---|
| Angreifer | Vom Angreifer kontrollierter Transaktionsabsender | NEAR | 20e6bfe4685d99004fc2095d3a0fc6158cd810ce8f801196141e183ed6e19d65 |
| Bösartiger Empfänger | Vertrag für Benachrichtigungs-Callbacks / Inhaber des internen Guthabens | NEAR | dd1fe58ec316ada5b673b88c14fe2fa2b7ede82080440901dfbd64b994241757 |
| Füll-Token | Vom Angreifer bereitgestellter Token zum Auffüllen des Batches | NEAR | 4444119_ |
Repräsentation von USDT |
Auf NEAR repräsentierter Vermögenswert von BNB Chain | NEAR | 56_2CMMyVTGZkeyNZTSvS5sarzfir6g |
USDT |
Zugrunde liegender Token | BNB Chain | 0x55d398326f99059ff775485246999027b3197955 |
| Intents | Vertrag für die interne Abwicklung | NEAR | intents.near |
| HOT Omni Balance | Token-Ledger nach NEP-245 | NEAR | v2_1.omni.hot.tg |
| BNB-Empfänger | Vom Angreifer kontrollierter Auszahlungsempfänger | BNB Chain | 0x09Fd1f5d9F185067A92493E43AA259ea4AB3ad37 |
| HOT Bridge-Vault | Cross-Chain-Vault für Vermögenswerte | BNB Chain | 0x233c5370CCfb3cD7409d9A3fb98ab94dE94Cb4Cd |
C. Erstellung des Füll-Tokens und Bridge-Transfers {#appendix-filler-token-origin}
Das Füll-Token entstand als benutzerdefinierter Osmosis-TokenFactory-Vermögenswert. Seine Erstellung, das Minting und die anschließenden Transfers verbinden es mit den Vorbereitungen für den Angriff. Alle nachstehenden Uhrzeiten gelten für den 29.09.2026 in UTC; das Einfordern auf NEAR ist Tx 2 in Anhang A.
| Uhrzeit (UTC) | Chain | Aktion | Transaktion |
|---|---|---|---|
| 14:00:29 | Osmosis | Token-Denomination erstellen | C489A91E... |
| 14:01:03 | Osmosis | 97e36 + 97 Roheinheiten minten |
5FD2CF0E... |
| 14:02:00 | Osmosis | Die gemintete Menge über IBC an Kava übertragen | 8EFD2659... |
| 14:02:32 | Kava | Dieselbe Menge über IBC an Gonka übertragen | D26EABBE... |
| 14:16:07 | Gonka | Den Vermögenswert bei HOT Bridge einzahlen | 41982DF3... |
| 16:09:34 | NEAR | Die zugehörige Repräsentation in HOT Omni Balance einfordern (Tx 2) | FmwaoRND... |
Dasselbe Osmosis-Konto erstellte, mintete und versendete das Token. Beide IBC-Transfers enthalten das Memo hot intents ctf filler. Die gemintete Menge von 97e36 + 97 Roheinheiten stimmt mit beiden Transfers, der Bridge-Einzahlung auf Gonka und dem Einfordern auf NEAR überein. Der Empfänger des Osmosis-Transfers ist der Absender des Kava-Transfers, dessen Empfänger wiederum der Absender der Bridge-Einzahlung auf Gonka ist. Zusammengenommen deuten diese Daten darauf hin, dass das Token im Rahmen der Angriffsvorbereitung erstellt wurde.
Der Gonka-Denom-Trace dokumentiert den IBC-Pfad transfer/channel-5/transfer/channel-1 und den ursprünglichen Osmosis-Vermögenswertidentifikator:
| Vermögenswertebene | Identifikator |
|---|---|
| Ursprüngliche Osmosis-Denomination | factory/osmo1dnjr753vam6 |
| Gonka-IBC-Denomination | ibc/C679139C206D0E7379C1 |
Die Base58-Dekodierung von contract_id in NEAR-Tx 2 ergibt die oben genannte Gonka-IBC-Denomination. Die Bridge-Einzahlung auf Gonka und das Einfordern auf NEAR haben die Nonce 1790691367000000007133 gemeinsam; der Empfänger-Hash der ursprünglichen Einzahlung stimmt zudem mit dem SHA-256-Hash der NEAR-Konto-ID des Angreifers überein. Diese Felder verbinden die ursprüngliche Einzahlung mit der Gutschrift auf NEAR. Die Bezeichnung Füll-Token beschreibt die Rolle dieses Vermögenswerts bei der Vergrößerung des Rückerstattungsereignisses.
D. Details zu den Receipts von Tx 5 {#appendix-tx5-receipts}
Die fünf nachstehenden zentralen Aktions-Receipts entsprechen den Schritten 5–8. Schritt 5 umfasst sowohl den anfänglichen Transfer über HOT Omni Balance als auch das Receipt der Einzahlung bei Intents.
| Zugehöriger Schritt | Receipt | Ausführende Instanz | Methode | Ergebnis |
|---|---|---|---|---|
| 5 | 8fWiEwQUbVATPC3J |
HOT Omni Balancev2_1.omni.hot.tg |
mt_batch_transfer_call() |
Erfolgreich; übertrug den Batch und plante mt_on_transfer() von Intents ein |
| 5 | DSfNwH18mEASbDg2 |
Intentsintents.near |
mt_on_transfer() |
Lokale Ausführung erfolgreich; gab ein Promise zurück |
| 6 | 7wwKtfGzK1YSGqT2 |
Bösartiger Empfängerdd1fe58ec316ada5 |
mt_on_transfer() |
Erfolgreich; gab ein Rückerstattungs-Array zurück |
| 7 | 4CPmVneKa1UWEuQa |
Intentsintents.near |
mt_resolve_deposit() |
Fehlgeschlagen: Protokolllänge überschritt den Grenzwert |
| 8 | 7y7VKm4tM3rEspHG |
HOT Omni Balancev2_1.omni.hot.tg |
mt_resolve_transfer() |
Erfolgreich; erstattete die übertragenen Vermögenswerte zurück |



