Während der letzten Woche (19.04.2026 - 26.04.2026) hat BlockSec acht Angriffsvorfälle mit geschätzten Gesamtschäden von ca. 7,04 Mio. $ erkannt und analysiert. Die folgende Tabelle fasst diese Vorfälle zusammen, und detaillierte Analysen für jeden Fall werden in den folgenden Unterabschnitten bereitgestellt.
| Datum | Vorfall | Typ | Geschätzter Schaden |
|---|---|---|---|
| 19.04.2026 | Custom Rebalancer Contract | Arbitrary Call | ~64 Tsd. $ |
| 20.04.2026 | REVLoans (Juicebox) | Improper Validation | ~50,7 Tsd. $ |
| 22.04.2026 | Volo Vault / Navi | Key Compromise | ~3,5 Mio. $ |
| 22.04.2026 | Kipseli Router | Improper Validation | ~72,35 Tsd. $ |
| 23.04.2026 | GiddyDefi | Incomplete Signature Validation | ~1,3 Mio. $ |
| 25.04.2026 | Purrlend | Key Compromise | ~1,5 Mio. $ |
| 26.04.2026 | SingularityFinance | Oracle Misconfiguration | ~413 Tsd. $ |
| 26.04.2026 | Scallop | Accounting Flaw | ~142,7 Tsd. $ |
Erste Schritte mit Phalcon Explorer
Tauchen Sie tief in Transaktionen ein, um klug zu handeln
Jetzt kostenlos testenWöchentliches Highlight: GiddyDefi
Der Angreifer knackte die Signatur nicht, verwendete keinen Flash-Loan und manipulierte keine Preise. Er spielte eine legitime Signatur mit vertauschten unsignierten Feldern gegen seinen eigenen Vertrag ab. "Benutze deine eigene Signatur gegen dich" ist die sauberste Demonstration dafür, wie eine partielle EIP-712-Abdeckung eine gültige Signatur in eine generische Genehmigung verwandelt.
Am 23. April 2026 wurde GiddyVaultV3 auf Ethereum für ca. 1,3 Mio. $ ausgenutzt. Das Signaturschema umfasste nur SwapInfo.data, wodurch aggregator, fromToken, toToken und amount außerhalb des EIP-712-Hashs lagen, sodass eine gültige Signatur mit manipulierten Feldern wiederverwendet werden konnte. Der Angreifer lenkte aggregator auf einen bösartigen Vertrag und fromToken auf den LP-Token der Strategie und entzog so ca. 1,3 Mio. $.
Hintergrund
GiddyVaultV3 (0x5f0a...4318) ist ein Yield-Farming-Vault-Vertrag, über den Benutzer Gelder über deposit() und withdraw() einzahlen und abheben. Jeder Vorgang muss eine von einem Backend signierte VaultAuth-Autorisierungsstruktur enthalten, die eine EIP-712-Signatur und ein SwapInfo[]-Array mit den Token-Swap-Routen enthält. Bei der Ausführung eines Swaps ruft der Vertrag GiddyLibraryV3.executeSwap() auf, der eine forceApprove auf swap.fromToken durchführt, die Genehmigung an swap.aggregator erteilt und dann den Swap über aggregator.call(swap.data) ausführt. Der Strategie-Vertrag verwaltet anschließend die Gelder gemäß seiner konfigurierten Strategie.
EIP-712 ist ein Standard zum Signieren strukturierter Off-Chain-Daten: das Protokoll, das die Signatur verwendet, rekonstruiert dieselbe Struktur On-Chain, hasht sie unter einem vereinbarten Domain-Separator und stellt die Adresse des Unterzeichners wieder her. Die Sicherheit eines jeden EIP-712-Flows hängt daher davon ab, dass der On-Chain-Hash alle Felder abdeckt, deren Wert die Ausführung beeinflusst. Im Design von Giddy signiert das Backend eine VaultAuth, die sowohl die Absicht des Benutzers als auch die Routing-Anweisungen für erforderliche Swaps enthält, und _validateAuthorization() rekonstruiert diese Struktur, um die Signatur zu überprüfen, bevor die Strategie Gelder bewegen darf.
Schwachstellenanalyse
Die Schwachstelle liegt in der Funktion _validateAuthorization() von GiddyVaultV3. Beim Erstellen der signierten Nutzlast wird nur das data-Feld jeder SwapInfo gehasht; aggregator, fromToken, toToken und amount sind alle von der Signatur ausgeschlossen. Das bedeutet, dass jeder, der im Besitz einer gültigen Signatur ist, die restlichen Felder von SwapInfo frei ersetzen kann, während die Signaturprüfung weiterhin bestanden wird.
Jedes ausgeschlossene Feld ist ein separater Hebel, den die Signatur frei lässt: aggregator wird sowohl zum Spender als auch zum Aufrufziel über forceApprove und aggregator.call(swap.data); fromToken wählt aus, welcher Strategie-Asset genehmigt wird; amount legt die Genehmigungs-Obergrenze fest; toToken dient nur einer returnAmount > 0-Prüfung. Die signierten data schränken keines davon ein, da keines dieser Ziele darin referenziert wird.

Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x5edb66...5482e5.
-
Schritt 1: Der Angreifer erhielt eine legitim vom Backend autorisierte
VaultAuth-Signatur aus der Blockchain und behielt dasdata-Feld intakt. Da jeder vorherigedeposit()- oderwithdraw()-Aufruf die vollständigeVaultAuth-Nutzlast auf der Blockchain sendete, war jede historische Transaktion eine kostenlose Quelle für eine wiederverwendbare Signatur; der Angreifer benötigte nur eine, derendata-Feld für den beabsichtigten Swap-Aufruf geeignet war. -
Schritt 2: Mit der erhaltenen Signatur behielt der Angreifer die ursprüngliche
signature,nonceunddataunverändert bei, während er die restlichen Felder manipulierte.fromTokenwurde auf den LP-Token gesetzt, den der Strategie-Vertrag hielt (ein echtes Asset), sodassforceApproveeine Genehmigung für einen Token erteilte, den das Protokoll tatsächlich hielt.aggregatorwurde durch den bösartigen Vertrag des Angreifers ersetzt, sodass sowohl die Genehmigung als auch der anschließendeaggregator.call()auf vom Angreifer kontrollierten Code gerichtet waren. Da diese Felder außerhalb des Signaturprüfungsbereichs lagen, akzeptierte_validateAuthorization()die manipulierte Struktur unverändert. Um die endgültige Prüfungrequire(returnAmount > 0, "SWAP_NO_TOKENS_RECEIVED")zu umgehen, implementierte der bösartige Aggregator eine Mint-Funktion, die gefälschte Token an das Protokoll zurückmintete und die Prüfung erfüllte, ohne einen echten Swap durchzuführen.


- Schritt 3: Da dem bösartigen Aggregator in Schritt 2 eine Genehmigung erteilt worden war, rief der Angreifer
transferFromauf, um die LP-Token des Vaults direkt an den bösartigen Aggregator zu übertragen und so den Diebstahl abzuschließen. Dieser Schritt lag vollständig außerhalb des geschützten Ausführungspfads des Protokolls; alsexecuteSwap()zurückkehrte, war die Genehmigung bereits geschrieben und die Nachkontrolle des Guthabens nach dem Aufruf bestanden, sodass das Protokoll keine weitere Möglichkeit hatte, einzugreifen.

Schlussfolgerung
Die Grundursache dieses Angriffs war die unvollständige EIP-712-Signaturabdeckung. Die Kernfelder von SwapInfo, die den Fluss der Gelder direkt steuern, blieben ungeschützt, sodass der Angreifer die Swap-Route und die Adresse des Aggregators austauschen konnte, während er eine gültige Signatur vorlegte. Entwickler, die externe Aggregatoren integrieren, sollten:
-
Sicherstellen, dass EIP-712-Signaturen alle Felder abdecken, die sich auf die Ausführungsergebnisse auswirken, einschließlich
aggregator,fromToken,toTokenundamount. -
Eine Whitelist für Aggregatoren erzwingen, um Aufrufe an nicht geprüfte externe Verträge zu verhindern.
-
toTokenauf erwartete Basistoken beschränken, um zu verhindern, dass gefälschte Token die Guthabenprüfungen umgehen.
Im Allgemeinen muss EIP-712 in jeder Architektur mit "Genehmigung dann Aufruf" jedes Feld hashen, das den resultierenden On-Chain-Status beeinflusst, nicht nur die benutzerorientierte Absicht. Immer wenn eine Backend-Signatur das alleinige Tor zwischen vom Benutzer bereitgestellten Parametern und einer privilegierten Vertragshandlung ist, müssen alle Parameter, die in diese Handlung einfließen (Aufrufziel, Asset, Betrag, Empfänger), innerhalb der signierten Struktur liegen. Die Behandlung von data als Proxy für die Identität des Aufrufs ist ein Kategorienfehler: die Identität des Aufrufs ist das Tupel aller seiner Parameter, und jeder Parameter, der außerhalb der Signatur verbleibt, wird per Definition von dem kontrolliert, der die Transaktion einreicht.
Bester Sicherheitsauditor für Web3
Validieren Sie Design, Code und Geschäftslogik vor dem Launch
Weitere Vorfälle diese Woche
Custom Rebalancer Contract
Am 19. April 2026 wurde ein sAVAX-Rebalancer-Vertrag auf Avalanche ausgenutzt, um ca. 64 Tsd. $ (~7.000 WAVAX) aus der Kreditdelegation eines Benutzers auf Aave V3 zu ziehen. Eine öffentliche Funktion führte einen beliebigen target.call(data) aus, während sie noch die Kreditdelegation des Benutzers hielt, sodass der Angreifer Aaves borrow() mit onBehalfOf auf das Opfer setzen konnte. Ein Whitehat-Bot hat den Exploit im Voraus ausgeführt und die Gelder vor jeder Auszahlung gerettet.
Hintergrund
Der Rebalancer-Vertrag (0x7a7b...a8c9) bietet eine Funktion b2a13230(), die dazu dient, die gehebelte Position eines Benutzers auf Aave neu auszubalancieren. Die Funktion operiert im Namen des Benutzers über die Aave V3-Kreditdelegation: der Benutzer erteilt dem Rebalancer die Erlaubnis, in seinem Namen zu leihen, und der Rebalancer kombiniert diese Kredite mit vom Benutzer bereitgestellten Geldern, um die Position anzupassen (z. B. ein Borrow + Supply-Workflow).
Schwachstellenanalyse
Die Grundursache ist, dass b2a13230() einen Schritt target.call(data) enthält, dessen Ziel und Calldata vom Aufrufer gesteuert werden. Dieser Aufruf erfolgt, während der Vertrag noch unter der Aave V3-Kreditdelegation des Benutzers operiert, sodass jede während dieses Schritts aufgerufene Logik die Kreditfähigkeit des Benutzers erbt. Es gibt keine Whitelist zulässiger Ziele und keine Formbeschränkung für die Calldata, sodass der Aufruf jede Vertragsmethode aufrufen kann, einschließlich Aaves borrow() mit dem Opfer als onBehalfOf.

Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion: 0xaaa1b2...35001b.
-
Schritt 1: Der Angreifer führte einen Flash-Loan über eine Menge an
sAVAXundUSDCdurch. Dann zahlte er den geliehenenUSDCüber den Rebalancer-Vertrag in Aave V3 ein, um eine ausreichende Besicherung für die Kreditaufnahme zu schaffen. In der Zwischenzeit wurde der geliehenesAVAXdirekt an den Rebalancer-Vertrag übertragen, um den anschließenden Versorgungsschritt nach der Kreditaufnahme vorzubereiten. -
Schritt 2: Der Angreifer rief die Funktion
b2a13230()auf. Die Funktion führte zunächst eine normale Kreditaufnahme durch und erreichte dann den Abschnitt für beliebige Aufrufe. Zu diesem Zeitpunkt führte der Angreifer den Aufruf so aus, dass dieborrow()-Funktion von Aave V3 direkt aufgerufen wurde, wobei das Opfer alsonBehalfOfangegeben wurde. Da das Opfer dem Rebalancer-Vertrag eine Kreditdelegation erteilt hatte, war die Kreditaufnahme erfolgreich. Der gelieheneWAVAXwurde in den Rebalancer-Vertrag übertragen.

- Schritt 3: Der Angreifer rief die Funktion
b2a13230()erneut auf und nutzte dabei den Rebalancer, umWAVAXin seinem eigenen Namen zu leihen. Der Vertrag nutzte dann den zuvor geliehenenWAVAX(der aus der Position des Opfers stammte), um ihn in die Position des Angreifers einzuspeisen und zurückzuzahlen, was es dem Angreifer ermöglichte, Gewinn zu erzielen.
Schlussfolgerung
Der Fehler ist die Kombination eines willkürlichen externen Aufrufs innerhalb eines privilegierten Kontexts, der über eine delegierte Kreditlinie verfügt. Jede Ebene allein wäre sicher: ein eingeschränkter externer Aufruf kann die Delegation nicht missbrauchen, und ein willkürlicher Aufruf ohne Delegation kann die Gelder des Benutzers nicht bewegen. Verträge, die Kreditlinien halten, sollten niemals einen willkürlichen externen Aufruf zulassen; wenn solche Aufrufe erforderlich sind, müssen Ziele einer Whitelist zugeordnet und die Calldata auf Form geprüft werden.
REVLoans (Juicebox)
Am 20. April 2026 wurde REVLoans, eine Kredit-Erweiterung auf Juicebox, auf Ethereum für ca. 50,7 Tsd. $ ausgenutzt. borrowFrom() akzeptierte eine vom Aufrufer bereitgestellte Buchhaltungsquelle, ohne zu überprüfen, ob sie im Protokoll registriert war; ein gefälschter 36-stelliger Kontext löste eine Same-Currency-Abkürzung aus, die die Guthaben um den Faktor 1e18 falsch skalierte. Zwei Transaktionen, eine zur Seed-Befüllung des aufgeblähten Buchhaltungseintrags und eine zur Kreditaufnahme gegen den legitimen Pool zum aufgeblähten Anteilspreis, entzogen 21,77 ETH.
Hintergrund
Juicebox ist ein hybrides Fundraising- und Kreditprotokoll auf Ethereum. Jedes Projekt hat seinen eigenen ERC20-Anteil-Token (hier als REV bezeichnet) und eine Kasse, die sich über einen oder mehrere Terminals verteilt, wobei ein Terminal der Vertrag ist, der physisch eine Teilmenge der Assets des Projekts verwahrt und als benutzerseitiger Ein-/Ausstiegspunkt dient. Ein Projekt kann mehrere Terminals, die in JBDirectory registriert sind, haben, und jedes (terminal, project, token)-Triple trägt einen JBAccountingContext, der die (decimals, currency) deklariert, die für die Buchhaltung dieses Tokens innerhalb dieses Terminals verwendet werden. REV ist daher ein Anspruch auf die Summe der Überschüsse über alle Terminals des Projekts, nicht ein Anspruch gegen einen einzelnen Terminal.
Ein Benutzer kann einen Asset in ein Terminal einzahlen im Austausch gegen neu geprägte REV, oder REV an einem Terminal für einen proportionalen Anteil am Überschuss einlösen (abzüglich einer konfigurierbaren Auszahlungssteuer, die etwas Wert für die verbleibenden Halter zurücklässt). REVLoans (0x2db6...1846), ein separater Vertrag, der darauf aufbaut, fügt eine Kreditfazilität hinzu: ein Benutzer verbrennt REV als Sicherheit und nimmt einen Kredit gegen eines der Terminals des Projekts auf, wobei der Kredit später im Austausch gegen die Neuprägung der Sicherheit zurückgezahlt werden kann. Der Kreditbetrag wird mit derselben Mathematik wie eine Einlösung bepreist, sodass eine Kreditaufnahme wirtschaftlich äquivalent zur Auszahlung derselben Sicherheit ist.
Der Anteilspreis von REV ist (totalSurplus + totalBorrowed) / (REV.totalSupply + totalCollateral). Die Einbeziehung von totalBorrowed im Zähler hält den Kredit-/Rückzahlungspreis neutral; sie bedeutet auch, dass ein aufgeblasener totalBorrowed den Anteilspreis direkt erhöht und einer kleinen Sicherheit eine unverhältlich hohe Auszahlung ermöglicht.
Schwachstellenanalyse
Die Grundursache ist eine nicht verifizierte Eingabe im Parameter source. borrowFrom() akzeptiert eine vom Aufrufer bereitgestellte REVLoanSource source (eine Struktur mit den Feldern .terminal und .token), ohne zu überprüfen, ob dieses Paar für die gegebene revnetId registriert ist. Beide Felder fließen direkt in die Auszahlungsmathematik ein, sodass der von source.terminal zurückgegebene Buchhaltungskontext vollständig vom Aufrufer gesteuert wird. Wenn das Feld currency dieses Kontexts mit dem des Zielterminals übereinstimmt, nutzt das Protokoll eine Same-Currency-Abkürzung, überspringt den Preis-Oracle und behandelt die bereitgestellten Dezimal- und Guthabenangaben als maßgeblich.

Die nicht validierte source wird dann von _addTo(), das ebenfalls keine Registrierungsprüfung durchführt, in _loanSourcesOf[revnetId] und totalBorrowedFrom[revnetId][source.terminal][source.token] geschrieben.

Sobald (source, revnetId) in der Buchhaltung steht, ist _borrowableAmountFrom() die Funktion, die eine Kreditierungsanforderung in einen zahlbaren Betrag übersetzt. Sie baut surplus = totalSurplus + totalBorrowed aus _totalBorrowedFrom() auf und übergibt diesen Überschuss dann zusammen mit der Anzahl der Sicherheiten des Aufrufers und dem Anteilsvorrat in JBCashOuts.cashOutFrom().

Der Dezimalfehler liegt eine Ebene tiefer, in _totalBorrowedFrom(). Er iteriert über _loanSourcesOf und faltet jeden Eintrag mittels mulDiv(tokensLoaned, 10**decimals, pricePerUnit). Auf dem Same-Currency-Pfad ist pricePerUnit = 10**decimals (die 18-stellige Präzision des Ziels), sodass die Formel auf tokensLoaned unverändert reduziert wird und ein unter 36-stelliger Buchhaltung gespeichertes Guthaben mit dem 18-stelligen ETH-Summe 1e18-mal zu groß landet.

Die Verstärkung erfolgt in cashOutFrom(). base = mulDiv(surplus, cashOutCount, totalSupply): bei surplus, das von aufgeblasenen totalBorrowed dominiert wird, entspricht selbst ein winziges cashOutCount (Sicherheit) einer unverhältlich großen Auszahlung.

Angriffsanalyse
Der Angriff verwendet zwei Transaktionen. Die erste verseucht die Buchhaltung von REVLoans: 0xc46cb7...dead1f. Die zweite entzieht den Pool gegen einen legitimen Terminal: 0x9adbd6...a8f938.
- Schritt 1: Der Angreifer rief
borrowFrom()mitterminalundtokenals Kreditquelle auf einen gefälschten Vertrag auf und hinterlegte eine kleine MengeREVals Sicherheit. REVLoans prüfte nicht, ob der bereitgestellte Terminal für das Revnet registriert war, noch ob der Token von ihm anerkannt wurde.

- Schritt 2: REVLoans forderte einen Buchhaltungskontext vom gefälschten Terminal an, der ein gefälschtes
(decimals=36, currency=ETH-Code(61166))zurückgab. Da die Quell- und Zielwährungen übereinstimmten, nutzte REVLoans eine Same-Currency-Abkürzung und übersprang den Preis-Oracle, dann führte es die Auszahlungsmathematik über die realenETH-Überschüsse der legitimen Terminals aus, die in der 36-stelligen Zieleinheit des Angreifers neu ausgedrückt wurden, und blähte die Zahl um den Faktor 1e18 auf.

- Schritt 3: REVLoans registrierte
(fake terminal, fake token)in_loanSourcesOfund schrieb die aufgeblasene Zahl intotalBorrowedFrom. Der gefälschte Terminal "zahlte aus", indem er den Empfang einfach bestätigte; es wurde kein echtesETHbewegt. Die erste Transaktion endete mit manipuliertemtotalBorrowednach oben und nur dem verbrannten kleinenREV-Collateral.

- Schritt 4: Der Angreifer rief erneut
borrowFrom()auf, diesmal mit dem legitimenETH-Terminal als Kreditquelle und einer winzigenREV-Sicherheit. Die Auszahlungsmathematik lief in echten 18-stelligenETH-Einheiten.

- Schritt 5: Bei der Berechnung von
totalBorrowediterierte REVLoans über_loanSourcesOfund stieß auf den Eintrag aus Schritt 3. Da diecurrencydieses Eintrags immer noch mitETHübereinstimmte, feuerte die Same-Currency-Abkürzung erneut und die gespeicherten 36-stelligen Guthaben wurden 1e18-mal zu groß in die 18-stelligeETH-Summe gefaltet.totalBorrowedwurde nun von gefälschten Schulden dominiert, und der Zähler des Anteilspreises war stark aufgebläht.

- Schritt 6: Die Auszahlungsmathematik lieferte einen Kreditbetrag, der auf den aufgeblähten Zähler abgestimmt war, den der Angreifer knapp unter dem realen Überschuss des legitimen Terminals voreingestellt hatte. Der legitime Terminal zahlte ihn aus und entzog fast den gesamten Pool an den Angreifer.

Schlussfolgerung
Die Grundursache sind zwei sich überlagernde Lücken: (terminal, token)-Paare werden ohne Überprüfung der Revnet-Registrierung akzeptiert, und die Same-Currency-Abkürzung faltet Quellguthaben in die Zielsumme, ohne die Dezimalunterschiede zu normalisieren. Jede Lücke allein wäre weniger gefährlich; zusammen erlauben sie einem Aufrufer, einen willkürlichen totalBorrowedFrom-Eintrag einzufügen und ihn zum Nennwert auszuzahlen. Abhilfemaßnahmen: Überprüfen Sie (terminal, token) gegen die registrierten Terminals des Revnets und normalisieren Sie die Guthaben anhand der gespeicherten Dezimalgröße der Quelle, bevor Sie sie falten.
Volo Vault
Am 22. April 2026 verlor Volo, ein Yield-Vault auf Sui, der durch Routing von Benutzereinzahlungen in das Navi-Kreditprotokoll Zinsen erwirtschaftet, ca. 3,5 Mio. $, nachdem der private Schlüssel des Betreibers geleakt wurde. Der Vault-Vertrag hatte keinen Code-Fehler; der Angreifer führte einfach den legitimen Betreiberpfad mit gestohlenen Anmeldeinformationen aus und entzog Volos Navi-Einlagen.
Hintergrund
Volo ist der benutzerseitige Vault (0xcd86...27fefa); Navi ist das zugrunde liegende Kreditprotokoll. Der Vault hält eine Navi AccountCap (ein Sui-Berechtigungs-Objekt, das Auszahlungen vom Navi-Konto von Volo autorisiert) und delegiert Strategiebewegungen an eine Betreiberrolle. Um auf Navi einzuzahlen oder abzuheben, ruft der Betreiber start_op_with_bag_v2() auf, um die AccountCap aus dem Vault in eine temporäre Tasche zu heben, und dann verwenden deposit_with_account_cap() / withdraw_with_account_cap_v2() diese Kappe, um Gelder zu bewegen.
Schwachstellenanalyse
Die Grundursache ist ein betrieblicher Fehler/ein Fehler bei der Schlüsselverwaltung und nicht eine vertragsbasierte Schwachstelle. Der Volo-Strategiepfad delegiert die Auszahlungsautorität an denjenigen, der den privaten Schlüssel des Betreibers hält: start_op_with_bag_v2() führt nur zwei Prüfungen durch (assert_operator_not_freezed(operation, cap) und assert_single_vault_operator_paired(operation, vault.vault_id(), cap)), die beide nur verifizieren, dass die bereitgestellte Berechtigung der registrierte Betreiber ist. withdraw_with_account_cap_v2() akzeptiert dann jeden Aufrufer, der die gehobene AccountCap vorlegen kann. Jeder, der im Besitz des privaten Schlüssels des Betreibers ist, kann daher denselben Pfad ausführen, den legitime Vorgänge verwenden, und zwar ununterscheidbar.

Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion AQw9wM...3RUS.
- Schritt 1: Der Angreifer rief
start_op_with_bag_v2auf@volosui/volo-vault::operationmit dem geleakten Betreiber-Schlüssel auf und hob die NaviAccountCapin eine temporäre Tasche.

-
Schritt 2: Der Angreifer verwendete
bag::remove, um dieAccountCapaus der temporären Tasche zu extrahieren. -
Schritt 3: Der Angreifer rief
withdraw_with_account_cap_v2auf@navi-protocol/lending::incentive_v3mit der extrahiertenAccountCapauf und zog Volos Einlagen von Navi ab.

- Schritt 4: Der Angreifer verwendete
bag::add, um dieAccountCapzurückzulegen, schloss die Operation und überwies die Gelder ab.
Schlussfolgerung
Der Defekt ist strukturell: ein Betreiber-Schlüssel, volle Auszahlungsbefugnis, keine zweite Prüfung. Drei Änderungen reduzieren den Schaden durch eine Schlüsselkompromittierung. Die Aufteilung der Betreiberrolle in ein Multisig- oder Schwellenwertschema bedeutet, dass ein geleakter Schlüssel nicht allein eine Auszahlung autorisieren kann. Das Hinzufügen einer Zeitschleife für ausgehende Auszahlungen gibt ungewöhnlichen Anrufen ein anfechtbares Fenster vor der Abrechnung. Die Eingrenzung der Befugnisse des Betreibers auf Einzahlung und Neuausgleich, wobei benutzerspezifische Auszahlungen über einen separaten Pfad geleitet werden, verhindert, dass die Betreiberrolle überhaupt an die Gelder des Benutzers gelangt.
Kipseli Router
Am 22. April 2026 wurde der Kipseli Router auf Base für ca. 72,35 Tsd. $ ausgenutzt. Der Router verwendet ein Angebot, das von einem externen Nur-USDC-Quoter zurückgegeben wird, als rohen Ausgabetoken-Überweisungsbetrag, ohne zu überprüfen, ob der Ausgabetoken dem Quoted-Token entspricht. Ein Angreifer tauschte 0,04 WETH gegen cbBTC auf einem Pfad, den der Quoter tatsächlich nicht unterstützt, und erhielt den USDC-skalierten Rückgabewert des Quoters (92.610.395) als rohe cbBTC-Einheiten (≈0,926 cbBTC).
Hintergrund
Kipseli Router (0x579f...9a07) ist ein Swap-Ausführungsvertrag, der auf einem externen Quoting-System basiert. Der Vertrag ist nicht Open-Source; die folgende Analyse basiert auf seinem dekompilierten Bytecode, weshalb die Funktionsnamen als 4-Byte-Selektoren erscheinen (0xcce096f3(), 0x592(), 0xd88()). Anstatt Swap-Preise direkt aus On-Chain-AMM-Pools zu berechnen, fragt er den Quoter nach einem Ausgabebetrag (amountOut) und führt dann die Token-Übertragung basierend auf diesem Wert aus. Im Normalbetrieb sendet der Benutzer tokenIn an das Protokoll-Wallet, und der Router zieht tokenOut aus demselben Wallet und leitet es an den Empfänger weiter. Das Protokoll ist mit einem einzigen QUOTE_TOKEN konfiguriert, und die Quoting-Logik ist in USDC mit 6-stelliger Buchhaltung denominiert; das System ist nur für USDC-denominierte Angebote konzipiert.
Schwachstellenanalyse
Der Defekt erstreckt sich über zwei Schichten, die sich gegenseitig verstärken. Auf der Router-Seite ruft die Funktion 0xcce096f3() ein Angebot v0 über die Quoter-Funktion 0x592() ab und übergibt es unverändert an 0xd88() als tokenOut.transferFrom(_wallet, receiver, v0). Der Router prüft niemals, ob tokenOut dem QUOTE_TOKEN des Protokolls entspricht, sodass ein USDC-skalierter Wert (6-stellige Präzision) übertragen wird, als wäre er eine cbBTC-Menge (8-stellige Präzision). Auf der Quoter-Seite ist der zugrunde liegende PropAMM AMM ausschließlich für Token-zu-USDC-Paare konzipiert, akzeptiert aber nicht unterstützte Routing-Pfade (WETH → cbBTC), ohne zurückzusetzen, ignoriert tokenIn stumm und gibt einen USDC-skalierten Wert zurück, als wäre der Swap gültig.

Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x96edee...3db3bb.
- Schritt 1: Der Angreifer rief den Router mit
tokenIn=WETHundtokenOut=cbBTCauf. Der zugrunde liegende AMM unterstützte diesen Pfad nicht, setzte aber nicht zurück, und der Quoter0x592()gab einenUSDC-skalierten Wert von 92.610.395 (≈92,61USDC) zurück.

- Schritt 2: Der Router verwendete diesen Wert direkt als
cbBTC-Überweisungsbetrag. 0,04WETH(≈95 $) flossen übertransferFromhinein; 92.610.395 rohecbBTC-Einheiten (≈0,926cbBTC, ≈72,35 Tsd. $) flossen aus dem Protokoll-Wallet an den Angreifer.

Schlussfolgerung
Der Exploit tritt auf, weil auf beiden Seiten des Quoter-Aufrufs zwei Annahmen unüberprüft bleiben. Der Quoter geht davon aus, dass seine Ausgabe in seinem eigenen 6-stelligen USDC-Rahmen verbraucht wird; der Router geht davon aus, dass alles, was der Quoter zurückgibt, in den angeforderten tokenOut-Einheiten denominiert ist. Jede Korrektur behebt den Fehler:
-
Beim Router: Assert
tokenOut == QUOTE_TOKENoder konvertieren Sie dasUSDC-skalierte Angebot über ein Orakel intokenOut-Einheiten, bevor Sie es übertragen. -
Beim Quoter: Rücksetzung bei Routing-Pfaden, deren Token nicht für den unterstützten Paar-Satz registriert sind, anstatt stillschweigend einen
USDC-skalierten Fallback zurückzugeben.
Purrlend
Am 25. April 2026 verlor Purrlend, ein Kreditprotokoll auf HyperLiquid und MegaETH, ca. 1,5 Mio. $, nachdem ein privater Schlüssel kompromittiert wurde. Der Angreifer übernahm die Brückenrolle und prägte nicht gedeckte pTokens (Purrlends Aave-ähnliche Beleg-Token), nutzte diese pTokens dann als Sicherheit, um reale Assets aus dem Pool zu leihen.
Hintergrund
Purrlend (0x81d5...a702) ist ein Kreditprotokoll mit einem Aave-ähnlichen Abrechnungsmodell. Wenn Benutzer Assets in das Protokoll einzahlen, erhalten sie entsprechende pTokens, ähnlich wie Aaves aTokens, die ihre Einzahlungsposition repräsentieren und als Sicherheit für die Kreditaufnahme anderer Assets verwendet werden können.
Das Protokoll umfasst auch privilegierte Rollen, darunter pool admin, risk admin und bridge. Die Brückenrolle ist für die plattformübergreifende Buchhaltung vorgesehen: sie kann pTokens prägen, um Einzahlungen auf einer Gegenstelle abzubilden. Die anderen Admin-Rollen ändern Risikoparameter und konfigurieren ausleihbare Assets.
Schwachstellenanalyse
Der unmittelbare Auslöser war eine Kompromittierung eines privilegierten Schlüssels: Der Angreifer erhielt die Schlüssel, die die Admin- und Brückenrollen von Purrlend kontrollierten. Ein Designfehler auf Vertragsebene verstärkte das Leck: Der pToken-Mint-Pfad der bridge-Rolle ist nicht an einen verifizierbaren Nachweis einer Cross-Chain-Hinterlegung gekoppelt. Die Funktion erlaubt einem Aufrufer mit Brückenrolle, pTokens an jede Adresse in beliebiger Menge auszugeben, ohne zu prüfen, ob auf der Quellseite eine entsprechende Einzahlung stattgefunden hat. Überall sonst im Protokoll werden pTokens als gültige Sicherheit behandelt, und der Kreditpfad prüft die Deckung zum Zeitpunkt der Kreditaufnahme nicht erneut. Eine nicht autorisierte Brückenrollen-Mintung übersetzt sich daher direkt in Kreditkapazität, ohne ein zweites Tor zwischen Minting und Asset-Auszahlung.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0xb96cff...dbbf24 auf MegaETH.
- Schritt 1: Der Angreifer, der über kompromittierte privilegierte Schlüssel verfügte, verwendete einen
MultiSendCallOnly-Batch überGnosisSafeProxy, um sich selbst alspool admin,risk admin,bridgeundemergency adminüberACLManagereinzurichten, aktivierte dannWETHals ausleihbares Asset und setzte dessenBorrowCapauf 200.

-
Schritt 2: Als Brücke nutzte der Angreifer die Möglichkeit, eine große Menge
pTokensan seine eigene Adresse zu prägen. Der Brücken-Mint-Pfad führte keine Überprüfung der Cross-Chain-Hinterlegung durch, sodass die neuenpTokenskeine zugrunde liegenden Assets hatten, die sie deckten. -
Schritt 3: Der Angreifer nutzte die nicht gedeckten
pTokensals Sicherheit. Da der Kreditpfad jedenpToken-Saldo als gültige Einzahlungsposition behandelt, ohne die Deckung erneut zu prüfen, bestand die Sicherheitsprüfung undWETHwurde aus dem Pool geliehen.
Schlussfolgerung
Dies war eine Kompromittierung eines privaten Schlüssels, die durch einen Designfehler auf Vertragsebene verstärkt wurde. Die geleakten Schlüssel gaben dem Angreifer nur die beabsichtigte Autorität der Brückenrolle, aber diese Autorität beinhaltete ein unbeschränktes pToken-Minting, das sich direkt in ausleihbare Sicherheit übersetzt. Jede Ebene kann unabhängig gestrafft werden. Auf der Betriebsebene sollte die Brückenrolle in ein Multisig- oder Schwellenwertschema aufgeteilt werden, damit ein einzelner Schlüssel-Leak sie nicht ausüben kann. Auf der Vertragsebene sollte der Brücken-Mint eine verifizierbare Hinterlegungsprüfung tragen (z. B. eine Nachrichtenzusage eines vertrauenswürdigen Cross-Chain-Verifizierers) und bei fehlendem Nachweis zurücksetzen. Die Überprüfung des Nachweises zum Zeitpunkt des Mintings ist die haltbarere Lösung, da sie die Abhängigkeit von der Schlüsselverwaltung vollständig beseitigt.
SingularityFinance
Am 26. April 2026 verlor das dynBaseUSDCv3 Vault von SingularityFinance auf Base ca. 413 Tsd. $. Das Vault war mit einer ungültigen Uniswap V3-Gebührenstufe (42, die in V3 nicht existiert) konfiguriert, sodass das Preisorakel jedes Nicht-USDC-Assets zu einem nicht existierenden Pool aufgelöst wurde. Die Preisbildungsfunktion gab 0 stillschweigend zurück, anstatt zurückzusetzen, das Vault bewertete seine Nicht-USDC-Reserven mit Null, und ein Angreifer prägte fast die gesamte Anteilsupply, indem er eine winzige Menge USDC einzahlte, und löste dann die tatsächlichen zugrunde liegenden Assets ein.
Hintergrund
Das dynBaseUSDCv3 Vault (0x67b9...4dcd) hält mehrere ertragsgenerierende Token und bewertet Nicht-USDC-Reserven über Uniswap V3. Der Preisbildungshelfer getPrice(base, fee, quote, amount) löst das (base, quote, fee)-Tupel zu einem Uniswap V3-Pool über die Factory auf und liest dann den TWAP aus diesem Pool. Die totalAssets() des Vaults aggregiert die bewerteten Reserven; die Verhältnisse für die Prägung und Einlösung von Anteilen werden aus dieser Gesamtsumme abgeleitet.
Schwachstellenanalyse
Der Defekt liegt im frühen Rückgabepfad von getPrice(). Wenn IUniswapV3Factory.getPool(base, quote, fee) address(0) zurückgibt (kein Pool für die angegebene Gebührenstufe existiert), fällt die Funktion durch und gibt ihre null-initialisierte Variable price zurück, anstatt zurückzusetzen. Das Vault wurde mit fee=42 bereitgestellt, was keine der von Uniswap V3 unterstützten Stufen ist (500/3000/10000), sodass jeder Nicht-USDC-Token-Lookup diesen Pfad trifft. totalAssets() summiert sich daher nur ungefähr auf das USDC-Guthaben des Vaults, während die tatsächlichen ertragsgenerierenden Token null beitragen. Die Prägungs- und Einlösungsverhältnisse, die von totalAssets() abhängen, werden gegenüber diesem fast null-Nenner berechnet.

Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 0x00b949...8d3732.
-
Schritt 1: Der Angreifer führte einen Flash-Loan von ca. 100.000
USDCdurch. -
Schritt 2: Der Angreifer zahlte den
USDCin das Vault ein. DatotalAssets()nur dasUSDC-Guthaben zählte, bewertete das Vault sich selbst ungefähr mit dem Einzahlungsbetrag und der Angreifer erhielt fast 100 % der Anteil-Supply. -
Schritt 3: Der Angreifer löste die Anteile ein, was die zugrunde liegenden Reserven proportional zum Anteilseigentum verteilt. Der Angreifer erhielt einen großen Teil jedes ertragsgenerierenden Tokens, das das Vault hielt.
-
Schritt 4: Der Angreifer zahlte den Flash-Loan zurück und behielt die abgezogenen ertragsgenerierenden Token als Gewinn.
Schlussfolgerung
Zwei Prüfungen fehlten. Die Bereitstellung validierte fee=42 nicht gegen die unterstützten Stufen von Uniswap V3 (500/3000/10000); getPrice() gab 0 bei einem fehlenden Pool zurück, anstatt zurückzusetzen. Jede Korrektur ist ausreichend: Validieren Sie die Orakelparameter zur Konfigurationszeit oder setzen Sie bei getPool() == address(0) zurück. Als zusätzliche Sicherheit sollte die Logik zur Anteilprägung totalAssets() gegen einen externen Referenzwert prüfen, bevor Einzahlungen akzeptiert werden.
Scallop
Am 26. April 2026 verlor das Staking-Rewards-Programm von Scallop auf Sui ca. 142,7 Tsd. $. Die Funktion zur Aktualisierung der gutgeschriebenen Belohnungen eines Benutzers prüfte nicht, ob das übergebene Belohnungs-Tracking-Objekt mit dem Konto des Benutzers übereinstimmte, sodass ein Angreifer ein fiktives Punkteguthaben von einem verlassenen, lange ruhenden Belohnungs-Tracking-Objekt abrufen und gegen den legitimen Belohnungspool einlösen konnte, bis das Guthaben erschöpft war.
Hintergrund
Scallop ist ein Kreditprotokoll auf Sui. Neben seinem Kreditprodukt betreibt Scallop ein Spool-Programm: Benutzer zahlen einen einzelnen Asset in Scallops Markt ein, um MarketCoin<T> zu erhalten (die Kreditbeleg-Token; für SUI-Einzahlungen ist dies MarketCoin<SUI>, die On-Chain-Darstellung von "sSUI"), staken dann diese MarketCoin in einen Spool, um im Laufe der Zeit Protokollpunkte zu verdienen, die sie später gegen einen gepaarten RewardsPool gegen tatsächliche Belohnungstoken einlösen. Jeder Spool ist ein gemeinsam genutztes Sui-Objekt, das einen globalen Pro-Anteil-index verfolgt; jeder Benutzer besitzt ein persönliches SpoolAccount, das sein gestaktes Guthaben und die gutgeschriebenen points aufzeichnet.
Schwachstellenanalyse
Der Defekt liegt in spool::user::update_points: Die Funktion behauptet nicht account.spool_id == object::id(spool) (noch account.stake_type == spool.stake_type). Geschwistereinträge stake, unstake und redeem_rewards führen alle diese Bindungsprüfung beim Eintritt durch; nur update_points überspringt sie. Ohne die Prüfung kann spool_account::accrue_points account.points += stake * (spool.index - account.index) / 1e9 gegen jeden übergebenen Spool berechnen und dessen index so behandeln, als wäre er der eigene Belohnungsstrom dieses Kontos.

Der Pfad wird ausnutzbar, da Sui niemals gemeinsam genutzte Objekte sammelt: Ein verlassener Scallop-Spool, dessen stakes zu Staub zerfallen sind, sammelt weiterhin Belohnungsanteile (periodische Inkrementierung 1e9 * reward / stakes), sodass sein index im Laufe der Zeit kumulativ ansteigt und beliebig große Werte erreichen kann. Ohne die Bindungsprüfung kann update_points diesen aufgeblasenen index verwenden, um eine riesige Punkte-Delta in jedes Konto zu schreiben. Die verschmutzten points werden dann 1:1 gegen den RewardsPool des Ziel-Spools eingelöst, da das Konto legitim an diesen Ziel-Spool gebunden ist und die eigene Bindungsprüfung von redeem_rewards bestanden wird.
Angriffsanalyse
Die folgende Analyse basiert auf der Transaktion 6WNDjC...NfVL.
-
Schritt 1: Mit 0,2
SUIals Köder prägte der AngreiferMarketCoin<SUI>, rief dannnew_spool_account+stakegegen den Ziel-Spool auf, um einen legitim gebundenenSpoolAccountmitaccount.spool_id = target_spoolzu erstellen. -
Schritt 2: Der Angreifer rief
update_points<MarketCoin<SUI>>(donor_spool, account, clock)mitdonor_spoolals verlassenenSpoolauf. Derindexdes Spenders (≈8.91e14) wurde alspointsin das Konto geschrieben:points = stake * (8.91e14 - 1.19e9) / 1e9 ≈ 1.62e14. -
Schritt 3: Der Angreifer rief
redeem_rewards<MarketCoin<SUI>, SUI>(target_spool, target_rp, account)auf. Die Bindungsassertionen akzeptierten das Ziel-gebundene Konto, die innere Re-Accrue gab früh zurück, und die verschmutztenpointswurden zum 1:1-Satz des Belohnungspools bis zu seinem Guthaben umgerechnet:rewards = 150.098.061.595.978roheSUI. -
Schritt 4: Der Angreifer rief
unstakeundredeemauf, um den 0,2-SUI-Köder zurückzuerhalten, dannTransferObjects, um alles zu verschieben.
Schlussfolgerung
Die Korrektur besteht darin, die gleiche assert!(account.spool_id == object::id(spool)) Prüfung am Eingang von update_points hinzuzufügen, die stake, unstake und redeem_rewards bereits durchführen. Als zusätzliche Sicherheit könnte das Protokoll auch die von einem einzelnen accrue_points-Aufruf akzeptierte index-Delta begrenzen ( Deltas größer als eine konfigurierte Obergrenze ablehnen), sodass auch wenn die Bindungsprüfung in Zukunft erneut umgangen würde, kein einzelner Aufruf einem Konto eine points-Menge gutschreiben könnte, die unverhältnismäßig zu seiner tatsächlichen Stake-Dauer ist.
Über BlockSec
BlockSec ist ein Full-Stack-Anbieter für Blockchain-Sicherheit und Krypto-Compliance. Wir entwickeln Produkte und Dienstleistungen, die unseren Kunden helfen, Code-Audits (einschließlich Smart Contracts, Blockchains und Wallets) durchzuführen, Angriffe in Echtzeit abzufangen, Vorfälle zu analysieren, illegale Gelder zu verfolgen und AML/CFT-Verpflichtungen über den gesamten Lebenszyklus von Protokollen und Plattformen zu erfüllen.
BlockSec hat mehrere Blockchain-Sicherheitsarbeiten auf renommierten Konferenzen veröffentlicht, mehrere Zero-Day-Angriffe auf DeFi-Anwendungen gemeldet, mehrere Hacking-Angriffe blockiert, um mehr als 20 Millionen Dollar zu retten, und Milliarden von Kryptowährungen gesichert.
-
Offizielle Website: https://blocksec.com/
-
Offizielles Twitter-Konto: https://twitter.com/BlockSecTeam



