Drücken Sie ESC, um zu schließen

ERC-Sicherheitslücken: Leitfaden für DeFi-Architekten

Hi! Wenn du diesen Text liest, brennst du entweder extrem für Smart Contract Security oder du bastelst gerade am Architektur-Setup eines neuen DeFi-Protokolls – und dir geht ordentlich die Düse bei dem Gedanken, dass das Ganze morgen wegen irgendeiner dämlichen Schwachstelle komplett gegen die Wand fährt.

Glaub mir, ich bin in dem Space schon ewig dabei. Ich habe den ganzen Weg durchgemacht: von Hackathons, wo wir nachts bei Pizza und Energy Drinks Exploits auf Krampf zusammengeschustert haben, bis hin zum Sessel des CTOs einer Krypto-Exchange. Und weißt du was? Die allermeisten heftigen Hacks, die ich gesehen und analysiert habe (und einige, die ich im Audit im letzten Moment verhindern konnte), passieren nicht, weil die Kryptographie fehlerhaft war. Auch nicht, weil der Solidity-Compiler plötzlich gesponnen hat. Sie passieren wegen eines fundamentalen Unverständnisses darüber, wie sich ERC-Standards verhalten, wenn sie direkt miteinander interagieren.

Wir wiegen uns oft in falscher Sicherheit und denken, Standards bedeuten fehlerfreien Code. Aber der Teufel steckt im Detail der Implementierung und in fiesen Seiteneffekten. Lass uns mal genau anschauen, wo Architekten am häufigsten aufs Maul fliegen und wie du dein System so baust, dass du nachts auch wirklich pennen kannst.

1. Die unsichtbare Gefahr bei ERC-20: Der gefährliche Klassiker

Man sollte meinen, ERC-20 sei bis zum Gehtnichtmehr analysiert worden. Was soll da schon schiefgehen? Absolut alles, wenn du fremde Token ohne knallharte Validierung in dein Protokoll reinlässt.

Das Problem mit dem fehlenden Rückgabewert (The No-Return Dilemma)

Laut Spezifikation müssen transfer und transferFrom ein bool zurückgeben. In der Realität scheren sich aber etliche alte und extrem wichtige Token (beste Grüße an USDT und BNB auf einigen ihrer alten Kontrakte) einen feuchten Kehricht darum. Sie geben bei Erfolg einfach gar nichts zurück.

Wenn dein Kontrat jetzt über ein Standard-Interface ein bool erwartet:

// Absolutes No-Go, wenn du mit beliebigen Token arbeitest!
IERC20(token).transferFrom(msg.sender, address(this), amount);

Dann wird die Transaktion bei der Interaktion mit USDT gnadenlos abschmieren (revert), weil die EVM einen Rückgabewert auf dem Stack sucht, der schlichtweg nicht da ist. Oder noch schlimmer: Wenn du das Ergebnis gar nicht erst prüfst (also stumpf token.transfer(...) statt require(token.transfer(...)) schreibst), geben manche Token im Fehlerfall einfach ein false zurück, anstatt zu reverten. Dein Kontrakt läuft dann munter weiter, als wäre alles perfekt. Das Ergebnis? Der User hat sich gerade Guthaben aus dem Nichts herbeigequatscht.

Die Lösung: Vergiss direkte Aufrufe von transfer und transferFrom ein für alle Mal. Nutze stattdessen die SafeERC20-Bibliothek von OpenZeppelin und deren Methoden safeTransfer / safeTransferFrom. Die prüft unter der Haube den Low-Level-Rückgabewert und biegt selbst fehlerhafte Kontrakte sauber gerade.

Weird ERC-20 Tokens: Wenn der Standard zum Albtraum wird

Hier ist ein kleiner Spickzettel für Token, die sich absolut nicht so verhalten, wie es im Lehrbuch steht. Als Architekt musst du das zwingend in der Logik deiner Liquiditätspools auf dem Schirm haben.

Token-Typ (Weird ERC-20)Was ist der Haken?Warum ist das gefährlich für die Architektur?
Deflationary / Fee-on-Transfer (z. B. STA, PAXG)Ziehen direkt während des Transfers eine Gebühr ab.Du denkst, dein Kontrakt hat 100 Token erhalten, aber auf der Balance sind nur 99 gelandet. Deine interne Liquiditätsberechnung fliegt auseinander, es entsteht ein Defizit.
Upgradable Proxies (z. B. USDC, USDT)Die Logik des Tokens kann jederzeit von den Admins geändert werden.Das Thema Blacklists. Wenn deine Kontraktadresse gesperrt wird, sitzt deine komplette Liquidität für immer in der Falle.
Rebasing Tokens (z. B. AMPL)Die Balance auf den Wallets ändert sich dynamisch (das Supply passt sich an, um den Preis zu stabilisieren).Die Token-Balance deines Kontrakts kann sich plötzlich von selbst verringern oder erhöhen, ohne dass irgendeine Transfer-Funktion aufgerufen wurde.

2. ERC-721 und ERC-1155: Die Falle von onERC721Received und Reentrancy

Oh ja, mein absolutes "Lieblingsthema". Wie viele NFT-Marktplätze und Lending-Protokolle wurden wegen der sicheren Transfer-Funktionen schon komplett rasiert!

Wenn du safeTransferFrom bei ERC-721 oder ERC-1155 aufrufst, prüft der Token-Kontrakt, ob der Empfänger ein Smart Contract ist. Wenn ja, triggert er beim Empfänger den Hook onERC721Received bzw. onERC1155Received.

Warum? Um sicherzustellen, dass der Zielkontrakt überhaupt mit NFTs umgehen kann und die Dinger dort nicht für immer einfrieren.

Wo ist der Haken? Dieser Hook übergibt die Kontrolle mitten in deiner Transaktion an externen, völlig unkontrollierbaren Code – und zwar genau *bevor* du den internen State deines eigenen Kontrakts aktualisiert hast!

Code eines verwundbaren Mintings / Marktplatzes

Schau dir dieses Snippet an. Ich habe es extra so geschrieben, um den klassischen Architekturfehler zu demonstrieren: die eiskalte Verletzung des Checks-Effects-Interactions-Patterns.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
contract VulnerableNFCLending {
    // Speichert Infos über Sicherheiten: User => Token-ID => Ist Sicherheit aktiv
    mapping(address => mapping(uint256 => bool)) public hasCollateral;
    IERC721 public nftToken;
    constructor(address _nft) {
        nftToken = IERC721(_nft);
    }
    // User möchte Kredit gegen NFT-Sicherheit aufnehmen
    function depositCollateral(uint256 tokenId) external {
        // 1. Interactions: Wir transferieren das NFT an den Kontrakt
        // Triggert safeTransferFrom den onERC721Received-Hook auf dem Empfängerkontrakt?
        // Warte, der Empfänger sind hier ja WIR. Aber wenn der Kontrakt safeMint aufruft...
        // Lass uns das Szenario lieber auf eine Situation umschreiben, in der wir das NFT zurückgeben oder ein Angreifer den Flow hijackt.
        
        // Neues Szenario: Kontrakt gibt NFT zurück (z. B. beim Auszahlen der Sicherheit)
        // oder es ist ein Minting-Kontrakt, der erst transferiert und danach den State updatet.
    }
}

Ich zeige dir lieber ein sauberes Beispiel mit einer verwundbaren Mint-Funktion, das ist viel anschaulicher. Sagen wir, wir haben einen Kontrakt, bei dem man genau 1 Free Mint pro Wallet abgreifen kann.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract VulnerableMint is ERC721 {
    mapping(address => bool) public hasMinted;
    uint256 public currentTokenId;
    constructor() ERC721("DangerNFT", "DNFT") {}
    function freeMint() external {
        // Checks
        require(!hasMinted[msg.sender], "Brother, you already have one!");
        // Interactions (In _safeMint ist der Aufruf des externen Kontrakts versteckt!)
        _safeMint(msg.sender, currentTokenId);
        currentTokenId++;
        // Effects (Das Update des States passiert VIEL ZU SPÄT)
        hasMinted[msg.sender] = true;
    }
}

Und hier kommt der Kontrakt des Angreifers. Er fängt diesen Hook einfach ab, sieht, dass hasMinted im Hauptkontrakt immer noch auf false steht, und ballert den Call für freeMint wieder und wieder rein, bis das Limit komplett leergeräumt oder sein Gas alle ist.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IVulnerableMint {
    function freeMint() external;
}
contract Attacker {
    IVulnerableMint public target;
    uint256 count;
    constructor(address _target) {
        target = IVulnerableMint(_target);
    }
    function attack() external {
        target.freeMint();
    }
    // Der verfluchte Hook, den der ERC-721-Standard aufruft
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external returns (bytes4) {
        if (count < 5) {
            count++;
            // Reentrancy-Angriff! Der interne State des Opfers wurde noch nicht geupdatet
            target.freeMint();
        }
        return this.onERC721Received.selector;
    }
}

Gott, wie oft ich genau das in Audit-Sessions gesehen habe. Die Devs denken sich: „Passt schon, ist doch nur ein NFT-Transfer, wir verschicken ja keine nativen ETH, was soll schon passieren?“ Was passiert, ist, dass dir die Hütte komplett leergeräumt wird.

Die goldene Regel für Architekten: Aktualisiere IMMER zuerst deinen State (hasMinted[msg.sender] = true;) und rufe erst danach irgendwelche Mint- oder Transfer-Methoden auf. Und pack verdammt noch mal standardmäßig den nonReentrant-Modifier von OpenZeppelin auf jede Funktion, die mit NFT-Transfers hantiert.

Weiter im Text. Nachdem wir das Thema Reentrancy über Hooks zerlegt haben, graben wir jetzt ein neueres und weitaus fieseres Problem aus. Beim Design der Systemarchitektur hat das kaum jemand auf dem Schirm – bis es auf Mainnet kracht.

3. ERC-2612 (Permit): Phantom-Approvals und Front-running-Attacken

Der ERC-2612-Standard hat der Web3-Welt eine massive Erleichterung beschert: die permit-Funktion. Damit können User eine Nachricht offline signieren (EIP-712), um ein Spending-Allowance zu erteilen. Die Gas-Gebühren werden einfach auf einen Relayer oder das Protokoll selbst abgewälzt. Der UX-Hebel ist brutal: Statt zwei Transaktionen (approve + transferFrom) braucht der User nur noch eine einzige Interaktion.

Viele Architekten vergessen aber, wie diese Signatur unter der Haube abläuft, und bauen fatale Logikfehler in ihre Smart Contracts ein.

Signatur-Front-running (Signature Front-running)

Stell dir eine klassische Deposit-Funktion vor, die permit nutzt:

function depositWithPermit(
    uint256 amount,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external {
    // Zuerst führen wir das permit mit der Signatur des Users aus
    IERC20Permit(token).permit(msg.sender, address(this), amount, deadline, v, r, s);
    
    // Danach holen wir uns die Token
    IERC20(token).transferFrom(msg.sender, address(this), amount);
    
    // Interne Pool-Shares oder Punkte minten
    _mintShares(msg.sender, amount);
}

Wo ist hier die Schwachstelle? Jeder MEV-Bot im öffentlichen Mempool sieht diese Transaktion sofort. Der Bot kann die valide Signatur (v, r, s) und die Parameter aus deiner TX extrahieren, eine eigene Transaktion bauen, token.permit(...) direkt auf dem Token-Contract aufrufen und den User per höherer Gas Price front-runnen.

Die Transaktion des Bots wird zuerst ausgeführt. Die Signatur wird erfolgreich verarbeitet, das Allowance ist gesetzt. Direkt danach kommt die TX des ehrlichen Users an die Reihe. Da die Signatur aber bereits verbraucht wurde, hat sich die Nonce des Users im Token-Contract erhöht! Der Aufruf von permit innerhalb von depositWithPermit läuft unweigerlich in einen revert, weil die Signatur ungültig geworden ist.

Das Ergebnis? Die User-Transaktion schlägt fehl, das Gas ist verbrannt, die UX komplett im Eimer. Wenn das ein zeitkritischer Margin-Top-up für eine gehebelte Long-Position war, wird der User wegen der Verzögerung eiskalt liquidiert.

Wie schützt man die Architektur?

Pack den permit-Aufruf in einen try/catch-Block. Wenn die Signatur bereits von einem Front-runner ins Netzwerk gepusht wurde, hat der Token-Contract das nötige allowance ja schon registriert. Dein Contract sollte den Fehler der duplizierten Signatur einfach ignorieren und eiskalt mit dem transferFrom weitermachen.

try IERC20Permit(token).permit(msg.sender, address(this), amount, deadline, v, r, s) {} 
catch {
    // Wenn es knallt, wurde die Signatur vermutlich schon ge-front-runned.
    // Wir prüfen, ob das aktuelle Allowance für die Operation ausreicht.
    require(IERC20(token).allowance(msg.sender, address(this)) >= amount, "Permit failed and allowance insufficient");
}

Das "Phantom Permit"-Problem

Das hier ist purer Insider-Schmerz, über den man fast nirgends liest. Was passiert, wenn dein DeFi-Protokoll beliebige Token unterstützt und ein User versucht, depositWithPermit für einen Asset aufzurufen, der ERC-2612 überhaupt NICHT implementiert hat?

Du denkst dir wahrscheinlich: "Na ja, dann schlägt die TX eben fehl, weil die permit-Funktion fehlt." Falsch gedacht – nicht immer!

Wenn der Token-Contract eine generische fallback()- oder receive()-Funktion hat, die bei einem unbekannten Function Selector keinen Revert auslöst (wie es bei manchen Proxy-Architekturen oder alten WETH-Token der Fall ist), läuft der permit-Aufruf scheinbar erfolgreich durch (gibt success = true zurück). In der Realität wurde aber logischerweise kein einziges Allowance erteilt.

Danach will dein Contract das transferFrom ausführen. Das scheitert dann zwar, es sei denn, es lag noch ein altes Approval vor. Wenn du diese Schwachstelle aber mit einer Logik kombinierst, bei der das Allowance über Umwege validiert wird, wirst du hardcore ge-rekt. Überprüf immer via ERC-165, ob der Ziel-Token IERC20Permit wirklich nativ unterstützt, oder fahre ein striktes Token-Whitelisting.

4. ERC-3156 (Flash Loans): Die Gefahr von Balance-Manipulationen innerhalb einer einzigen Transaktion

Flash Loans sind ein mächtiges Werkzeug, aber sie hebeln die zeitlichen Annahmen aus, an die klassische Software-Architekten gewöhnt sind. Innerhalb einer einzigen atomaren Transaktion kann ein Angreifer Millionen Dollar leihen, das System verbiegen und die Kohle am Ende wieder zurückzahlen.

Der fatalste Architekturfehler überhaupt ist es, die Funktion balanceOf(address(this)) zu nutzen, um den Wert von Pool-Shares oder Asset-Preisen zu berechnen.

// KATASTROPHALER FEHLER IN DER ARCHITEKTUR
function getSharePrice() public view returns (uint256) {
    // Der Share-Preis hängt direkt vom aktuellen Token-Guthaben des Contracts ab
    return token.balanceOf(address(this)) / totalShares;
}

Wenn dein Contract Flash Loans für genau diesen Token erlaubt, droppt die Balance des Contracts in dem Moment, in dem der Kreditnehmer die Token abzieht, fast auf Null. Wenn dein Protokoll exakt in diesem Bruchteil einer Sekunde (innerhalb des onFlashLoan-Callbacks) andere Operationen zulässt – wie Liquidationen oder Rewards-Berechnungen –, ist der berechnete Share-Preis komplett verzerrt.

Der Hacker zieht den Flash Loan -> Pool-Balance schrumpft -> Share-Preis crasht in den Keller -> Hacker kauft über eine zweite Wallet extrem billig Pool-Shares auf -> Flash Loan wird zurückgezahlt -> Pool-Balance erholt sich -> Hacker dumper die Shares zum regulären Preis. Pool leergeräumt.

Goldene Regel: Verlass dich bei kritischen mathematischen oder ökonomischen Berechnungen niemals auf balanceOf(address(this)), wenn diese Balance temporär manipuliert werden kann, ohne den logischen Zustand des Systems dauerhaft zu verändern. Nutze stattdessen internes Accounting über eine State-Variable wie uint256 internalReserve, die ausschließlich bei kontrollierten Deposits und Withdrawals angefasst wird.

Alles klar, kommen wir zu den Dingen, bei denen mir als Verantwortlichem für die Sicherheit der Exchange-Infrastruktur echt die Haare zu Berge stehen. Reden wir über neue und relativ frische Standards, bei denen die Fehlerquellen noch nicht von Hunderten von Entwicklern plattgetrampelt wurden.

5. ERC-4337 (Account Abstraction): Fallstricke auf Ebene von Batch-Transaktionen und Paymastern

Account Abstraction ist verdammt cool, gar keine Frage. Wir bewegen uns weg von EOAs (klassischen Wallets) hin zu Smart Contracts als User-Wallets. Keine Seedphrases mehr, Social Recovery ist möglich und die Gas-Gebühren können via Paymaster direkt in Stablecoins bezahlt werden.

Aber aus der Sicht eines Protokoll-Architekten, der ERC-4337 integrieren will, tut sich hier ein tiefer Abgrund hochspezifischer Angriffsvektoren auf.

Die Signatur-Schwachstelle in validateUserOp

Bei ERC-4337 ist die Methode validateUserOp der Dreh- und Angelpunkt für die eigene Validierungslogik des Wallets. Sie muss die Signatur der Transaktion überprüfen und einen speziellen Status zurückgeben.

// Vereinfachtes Beispiel für die Validierungslogik in einem Smart Wallet
function validateUserOp(
    UserOperation calldata userOp,
    bytes32 userOpHash,
    uint256 missingAccountFunds
) external returns (uint256 validationData) {
    // Kritischer Fehler: Vertrauen wir hier dem Aufruf von JEDER beliebigen Adresse?
    // Nein, der Bundler ruft das über den EntryPoint auf. Wenn wir aber den Check vergessen...
    require(msg.sender == entryPoint, "Only EntryPoint can trigger validation");
    
    // Eigene Signatur-Validierung
    if (_verifySignature(userOp, userOpHash)) {
        // Return 0, wenn die Validierung erfolgreich war
        return 0; 
    }
    
    // Return SIG_VALIDATION_FAILED (normalerweise 1) bei Fehlern
    return 1; 
}

Warte mal, merkst du, wo hier der Haken liegt? Laut ERC-4337-Spezifikation darf die Funktion bei einer fehlgeschlagenen Signatur-Validierung KEIN revert auslösen. Sie muss stattdessen einen speziellen gepackten Wert (eine Fehlerkonstante) zurückgeben, damit der EntryPoint (der Hauptvertrag bzw. Dirigent) checkt, dass die Transaktion ungültig ist. So wird kein Gas vom Wallet abgezogen und die Operation wird einfach direkt auf Bundler-Ebene gedroppt.

Wenn du da als Architekt aus Gewohnheit ein require(isValid, "Invalid signature"); reinklatschst, baust du dir eine heftige Schwachstelle. Wenn ein ganzer Schwung Transaktionen als Batch gesendet wird, zerschießt eine einzige gefailte Transaktion wegen des harten revert den kompletten Batch für den Bundler. Das Ende vom Lied: Dein Wallet oder dein Paymaster landet bei den Bundlern auf der Blacklist (Ban) und deine User können überhaupt keine Transaktionen mehr rausschicken. Die Validierungslogik muss atomar sein und strikt der Return-Value-Mathematik von ERC-4337 folgen, statt klassischen Solidity-Mustern.

Angriff auf den Paymaster (Gas Drain)

Wenn dein DeFi-Protokoll als Paymaster fungiert (weil du zum Beispiel das Gas für deine User subventionierst, damit sie ohne Gebühren traden können), musst du die Validierungsphase absolut wasserdicht von der Außenwelt isolieren.

Im Paymaster-Contract gibt es die Methode validatePaymasterUserOp. Innerhalb dieser Methode ist es **strikt verboten**, dynamische States zu nutzen, die sich zwischen der Simulation der Transaktion durch den Bundler und dem eigentlichen Einschluss in den Block ändern können. Du darfst beispielsweise keine Preis-Oracles (wie Chainlink) direkt in der Paymaster-Validierung aufrufen, um zu berechnen, wie viele Token dem User für das Gas abgezogen werden müssen.

**Warum?** Ein Angreifer könnte eine Transaktion senden; während der Simulation zeigt das Oracle einen bestimmten Preis (Validierung geht durch), aber direkt vor dem Block-Inclusion manipuliert der Hacker den Oracle-Preis selbst (via Flashloan oder schnellem Trade). Die On-Chain-Validierung fliegt auf die Nase, aber der Bundler hat die Transaktion bereits verarbeitet und Gas verbrannt. Die Kohle wird von deinem Paymaster abgebucht, während der User keinen Cent zahlt. Dein Gas-Guthaben wird so in wenigen Stunden komplett leergesaugt.

6. ERC-4626 (Tokenized Vaults): Frontrunning beim ersten Deposit (Inflation Attack)

ERC-4626 ist der Goldstandard für tokenisierte Vaults (Staking, Yield Pools, Lending). Er hat die Methoden deposit, mint, withdraw und redeem vereinheitlicht. Das ist genial, weil jetzt jeder Yield-Aggregator wie Yearn einen neuen Pool innerhalb von 5 Minuten integrieren kann.

Allerdings ist im mathematischen Design des Standards eine tickende Zeitbombe verbaut, die als **Inflation Attack** bekannt ist. Sie trifft Pools genau in dem Moment, in dem sie frisch im Netzwerk deployed werden und ihre Gesamtbalance noch bei null steht.

Mechanik des Angriffs

Die Formel zur Berechnung der Anteile (Shares), die ein Nutzer beim Einzahlen von Assets erhält, sieht meistens so aus:

$$\text{shares} = \frac{\text{assets} \times \text{totalShares}}{\text{totalAssets}}$$

Wenn der Pool komplett leer ist (totalShares == 0), gilt standardmäßig shares == assets. Also ein sauberes 1-zu-1-Verhältnis.

Und jetzt schau genau hin, wie der Hacker das System austrickst:

  • Ein ehrlicher User schickt eine deposit-Transaktion über 1.000 USDC an einen brandneuen, leeren ERC-4626-Pool.
  • Der Hacker sieht das im Mempool und frontrunned die Transaktion (gibt mehr Gas). Er zahlt mickrige 1 Wei USDC in den Pool ein. Der Pool mintet ihm exakt 1 Wei an Shares. Der aktuelle Stand: totalShares = 1, totalAssets = 1.
  • Direkt danach – noch in derselben atomaren Transaktion – transferiert der Hacker eine riesige Summe (sagen wir 10.000 USDC) direkt per normalem ERC20-transfer an die Adresse des Pool-Contracts (also ohne die deposit-Funktion zu nutzen).
  • Was passiert mit der Pool-Mathematik? totalShares ist immer noch 1, aber die totalAssets stehen plötzlich bei 10.001 USDC (durch den direkten Transfer ist die Balance des Contracts explodiert, ohne dass neue Shares gemintet wurden). Der Preis für ein einzelnes Share schießt damit komplett durch die Decke.
  • Jetzt erst wird die Transaktion des ehrlichen Users über die 1.000 USDC ausgeführt. Der Contract berechnet die Shares nach der Formel:

    $$\text{shares} = \frac{1000 \times 1}{10\,001} = 0$$

    Wegen des Abrundens (Integer-Division) in Solidity erhält der User unterm Strich genau 0 Shares! Seine 1.000 USDC wandern aber trotzdem erfolgreich auf die Balance des Pools.

  • Der Hacker muss jetzt nur noch ein withdraw für sein einziges Share (1 Wei Shares) triggern und räumt den kompletten Pool leer: Er kriegt seine 10.000 USDC zurück, sein ursprüngliches 1 Wei und die abgezockten 1.000 USDC des ehrlichen Users.

Architektonische Lösung: Dagegen schützen kann man sich im Wesentlichen auf zwei Wegen. Erstens: Direkt beim Erstellen des Pools erzwingt man das Minten von "Dead Shares" an die Zero-Address (man sperrt die ersten 1.000 Wei an Shares dort ein, genau wie bei Uniswap V2). Zweitens: Man nutzt die aktuellen OpenZeppelin-Bibliotheken, die einen integrierten Schutz über virtuelle Offsets (virtual assets und virtual shares) bieten. Das verhindert, dass der Nenner des Bruchs bei solchen Manipulationen auf null oder eins sinken kann.

Hör mal, lass uns jetzt mal eine Stufe höher schalten. Wir haben über einzelne Tokens, NFTs, Permits und Vaults gesprochen. Aber wie verknüpft man den ganzen Kram zu einer sauberen Architektur, ohne bei der Integration komplett durchzudrehen?

Wenn du ein größeres System designst, wie etwa einen Yield Aggregator oder eine Cross-Chain-Bridge, musst du mit all diesen Standards gleichzeitig jonglieren. Und genau da entsteht dieser synergetische Effekt bei den Vulnerabilities: Zwei Features, die für sich genommen absolut safe sind, können in Kombination plötzlich eine fatale Sicherheitslücke aufreißen.

7. Architektur-Risikomatrix für System-Designs

Damit du den Durchblick behältst, habe ich dir diese Tabelle zusammengestellt. Das ist quasi die Checkliste für deinen nächsten Architecture Review. Pack sie dir in Notion oder druck sie dir aus.

ERC-StandardDie größte versteckte GefahrLogik-ImpactDesign-Fix
ERC-20Fehlende Rückgabewerte / Non-Standard TransferTransaction Revert oder stillschweigendes Ignorieren von FehlernVerwende ausschließlich SafeERC20 (OpenZeppelin).
ERC-20 (Weird)Fee-on-Transfer / Balance-Änderung (Rebase)Diskrepanz zwischen interner Buchhaltung und echtem Contract-BalanceBerechne die Differenz balanceAfter - balanceBefore, statt dem amount-Argument blind zu vertrauen.
ERC-721 / 1155Control-Hijacking via onERC...Received HooksReentrancy vor dem Update des internen StatesStriktes Checks-Effects-Interactions Pattern + nonReentrant Modifikator.
ERC-2612Frontrunning von Signaturen im MempoolDenial-of-Service (DoS) für legitime UserKapsele permit-Aufrufe in try/catch-Blöcke.
ERC-3156Temporäres Leersaugen des Pools (Flash Loan)Manipulation von Spot-Preisen, die auf balanceOf basierenVerwende interne Reserven (internal reserves) statt direkt das Balance-Mapping.
ERC-4337Hard revert bei der Batch-ValidierungBann des Contracts/Wallets durch BundlerGib magische Fehler-Konstanten zurück, statt die TX per require zu killen.
ERC-4626Inflation Attack (Exploit beim ersten Deposit)Rundungsfehler bei Shares, Diebstahl der Assets des ersten EinzahlersMinte beim Initialisieren "Dead Shares" auf address(0) oder nutze virtuelle Offsets.

8. Thoughts & Goldene Regeln für eine sichere Architektur

Weißt du, nach drei Jahren auf dem CTO-Stuhl hab ich eine Sache gelernt: Der sicherste Code ist der, den du gar nicht erst geschrieben hast. Je komplexer dein Architektur-Schema, desto mehr versteckte Abhängigkeiten hast du – und desto höher die Chance, dass irgendein Hacker-Genie eine Lücke findet, an die du beim morgendlichen Kaffee noch nicht mal gedacht hast.

Wenn ich dir nur drei Regeln mitgeben könnte, die dein Projekt vor Rekt-News-Schlagzeilen bewahren, wären das diese:

  • Vertrau niemals externen Contracts. Auch nicht, wenn es der größte Token der Welt ist. Morgen ändern die Admins den Proxy, hauen Blacklists rein und dein System steht still. Codiere immer so, als wäre der externe Token der bösartigste und unberechenbarste Akteur im Netz.
  • Erst State, dann Transfer. Ich kann es nicht oft genug sagen. Das ist das Einmaleins, das dir in jedem Kurs eingebläut wird, aber Leute mit dem Stolz eines Maniacs feuern Tokens raus, bevor sie ihre Mappings updaten. Erst ziehst oder gibst du Rechte intern, fixierst das auf der Blockchain und ganz zum Schluss triggerst du externe transfer, safeMint oder call Befehle.
  • Isoliere deine Mathe vom externen Balance. Die Balance deines Contracts in der EVM ist public und lässt sich kinderleicht manipulieren. Jeder kann dir via Flash Loan Millionen reindrücken oder per selfdestruct Ether auf deine Adresse zwingen. Wenn deine Logik für Rewards oder Share-Preise direkt vom Contract-Balance abhängt, hast du schon verloren. Deine interne Buchhaltung muss so isoliert sein wie das Cockpit eines Piloten.

Damit haben wir die kritischsten Schmerzpunkte der Standards abgegrast. Selbst das stärkste Dev-Team kann baden gehen, wenn der Architekt nicht rechtzeitig die richtigen Sicherheits-Patches in die Struktur eingebaut hat.

Oleg Filatov

As the Chief Technology Officer at EXMON Exchange, I focus on building secure, scalable crypto infrastructure and developing systems that protect user assets and privacy.

With over 15 years in cybersecurity, blockchain, and DevOps, I specialize in smart contract analysis, threat modeling, and secure system architecture.

At EXMON Academy, I share practical insights from real-world...

...

Diskussion beitreten

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *