# Attaques par Flash Loan Expliquées — Comment des Millions Sont Volés
Les flash loans sont l'une des fonctionnalités les plus innovantes de la DeFi — et l'un de ses vecteurs d'attaque les plus exploités. En 2021 seulement, plus de 300 millions de dollars ont été volés via des attaques par flash loan.
Bien qu'étant une primitive DeFi légitime, les flash loans amplifient les vulnérabilités existantes, permettant aux attaquants de manipuler les marchés, les oracles, et la gouvernance avec zéro capital initial.
Dans cet article, nous allons disséquer comment fonctionnent les attaques par flash loan, examiner des exploits réels, et apprendre des stratégies de défense éprouvées.
Que Sont les Flash Loans ?
Un flash loan est un prêt non collatéralisé qui doit être emprunté et remboursé dans une seule transaction.
Caractéristiques Clés
- Pas de collatéral requis — n'importe qui peut emprunter des millions instantanément
- Transaction atomique — prêt + opérations + remboursement se produisent en un bloc
- Liquidité instantanée — accès à un capital massif sans le posséder
- Zéro risque pour le prêteur — si non remboursé, toute la transaction revert
Exemple (Flash Loan Aave)
interface IFlashLoanReceiver {
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool);
}
contract FlashLoanUser is IFlashLoanReceiver {
ILendingPool public lendingPool;
function executeFlashLoan(address asset, uint256 amount) external {
address[] memory assets = new address[](1);
assets[0] = asset;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
uint256[] memory modes = new uint256[](1);
modes[0] = 0; // Pas de dette
lendingPool.flashLoan(
address(this),
assets,
amounts,
modes,
address(this),
"",
0
);
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external override returns (bool) {
// Vous avez maintenant amounts[0] de assets[0]
// Faire quelque chose avec les fonds flash loaned
// ... votre logique ici ...
// Rembourser prêt + frais
uint256 amountOwed = amounts[0] + premiums[0];
IERC20(assets[0]).approve(address(lendingPool), amountOwed);
return true;
}
}
Pourquoi les Flash Loans Sont Dangereux
Les flash loans eux-mêmes ne sont pas malveillants, mais ils amplifient les vulnérabilités existantes en fournissant :
Vecteurs d'Attaque par Flash Loan
1. Manipulation d'Oracle
Type d'attaque le plus courant. Manipuler les oracles de prix pour exploiter les protocoles qui s'y fient.
Pattern d'Oracle Vulnérable
contract VulnerableLending {
IERC20 public tokenA;
IUniswapV2Pair public pair; // TokenA/WETH
// VULNÉRABLE : Utilisation du prix spot du DEX
function getPrice() public view returns (uint256) {
(uint112 reserve0, uint112 reserve1,) = pair.getReserves();
return (reserve1 * 1e18) / reserve0; // Prix instantané
}
function borrow(uint256 amount) external {
uint256 collateralRequired = (amount * getPrice()) / 1e18;
require(tokenA.balanceOf(msg.sender) >= collateralRequired);
// L'utilisateur peut emprunter basé sur prix manipulé
// ...
}
}
Scénario d'Attaque
contract OracleAttack {
function attack() external {
// 1. Flash loan grande quantité de TokenA
uint256 loanAmount = 1000000 * 1e18;
flashLoan(address(tokenA), loanAmount);
}
function executeOperation(/*...*/) external {
// 2. Dumper TokenA sur DEX, crasher le prix
tokenA.approve(address(router), loanAmount);
router.swapExactTokensForTokens(
loanAmount,
0,
path,
address(this),
block.timestamp
);
// Le prix est maintenant artificiellement bas
// 3. Emprunter montant massif du protocole de prêt
// (qui pense que le collatéral vaut plus à cause du prix TokenA bas)
lendingProtocol.borrow(exploitAmount);
// 4. Swap de retour pour restaurer le prix
router.swapExactTokensForTokens(/*...*/);
// 5. Rembourser flash loan
tokenA.transfer(lender, loanAmount + fee);
// L'attaquant garde les fonds sur-empruntés
}
}
Exemple réel : Harvest Finance (2020) — 24M$ volés via manipulation de prix sur les pools Curve.
2. Attaques de Gouvernance
Flash loan de tokens de gouvernance massifs pour passer des propositions malveillantes.
Gouvernance Vulnérable
contract VulnerableDAO {
IERC20 public govToken;
struct Proposal {
address target;
bytes data;
uint256 forVotes;
uint256 againstVotes;
bool executed;
}
mapping(uint256 => Proposal) public proposals;
// VULNÉRABLE : Snapshot au moment du vote, pas de création de proposition
function vote(uint256 proposalId, bool support) external {
uint256 votes = govToken.balanceOf(msg.sender);
if (support) {
proposals[proposalId].forVotes += votes;
} else {
proposals[proposalId].againstVotes += votes;
}
}
function execute(uint256 proposalId) external {
Proposal storage prop = proposals[proposalId];
require(prop.forVotes > prop.againstVotes);
require(!prop.executed);
prop.executed = true;
(bool success,) = prop.target.call(prop.data);
require(success);
}
}
Attaque
function governanceAttack() external {
// 1. Flash loan tokens de gouvernance
flashLoan(address(govToken), 51% of supply);
// 2. Créer proposition malveillante
dao.propose(address(treasury), abi.encodeWithSignature(
"transfer(address,uint256)",
attacker,
treasury.balance
));
// 3. Voter avec tokens flash loaned
dao.vote(proposalId, true);
// 4. Exécuter immédiatement (si pas de timelock)
dao.execute(proposalId);
// 5. Rembourser flash loan
govToken.transfer(lender, amount + fee);
}
Exemple réel : Beanstalk (2022) — 182M$ volés via prise de contrôle de gouvernance avec tokens flash loaned.
3. Amplification de Réentrance
Les flash loans fournissent du capital pour des attaques de réentrance sur des protocoles mal protégés.
function amplifiedReentrancy() external {
// 1. Flash loan montant important
flashLoan(10000 ether);
// 2. Déposer au protocole vulnérable
vulnerable.deposit{value: 10000 ether}();
// 3. Exploiter réentrance pour retirer répétitivement
vulnerable.withdraw(10000 ether);
// La réentrance draine plus que déposé
// 4. Rembourser flash loan
lender.transfer(10000 ether + fee);
// Garder l'excès
}
4. Manipulation de Liquidation
Manipuler les prix de collatéral pour déclencher des liquidations de masse, puis acheter le collatéral pas cher.
Attaques par Flash Loan Réelles
Harvest Finance (Octobre 2020)
- Volé : 24M$
- Méthode : Manipulation de prix pool Curve
- Flash loan de : Uniswap (pas de frais à l'époque)
- Résultat : Le protocole a survécu mais les utilisateurs ont perdu des fonds
PancakeBunny (Mai 2021)
- Volé : 45M$
- Méthode : Manipulation d'oracle de prix sur PancakeSwap
- Impact : Token BUNNY a chuté de 96%
Cream Finance (Août 2021)
- Volé : 18.8M$
- Méthode : Flash loan + manipulation oracle de prix sur token AMP
- Répétition : Cream a été hacké 3 fois en 2021
Beanstalk (Avril 2022)
- Volé : 182M$
- Méthode : Attaque de gouvernance par flash loan
- Loans de : Aave (1B$ emprunté)
- Exécution : Proposition malveillante passée, trésorerie drainée
Euler Finance (Mars 2023)
- Volé : 197M$ (retourné plus tard)
- Méthode : Flash loan + attaque par donation pour manipuler le tracking de dette
- Plus gros hack DeFi de 2023
Stratégies de Prévention
1. Oracles TWAP (Time-Weighted Average Price)
N'utilisez pas les prix spot. Utilisez des moyennes pondérées dans le temps qui ne peuvent être manipulées en une seule transaction.
contract TWAPOracle {
IUniswapV2Pair public pair;
uint256 public priceAverage;
uint256 public lastUpdate;
uint32 public constant PERIOD = 10 minutes;
function update() external {
uint32 timeElapsed = uint32(block.timestamp - lastUpdate);
require(timeElapsed >= PERIOD, "Too soon");
(uint256 price0Cumulative, uint256 price1Cumulative,) =
UniswapV2OracleLibrary.currentCumulativePrices(address(pair));
priceAverage = (price0Cumulative - price0CumulativeOld) / timeElapsed;
lastUpdate = block.timestamp;
price0CumulativeOld = price0Cumulative;
}
function getPrice() external view returns (uint256) {
return priceAverage; // Résistant à la manipulation
}
}
Pourquoi ça marche : Les attaques par flash loan se produisent en une transaction. TWAP nécessite des changements de prix sur plusieurs blocs.
2. Price Feeds Chainlink
Utilisez des oracles de prix décentralisés, externes, qui ne peuvent être manipulés via des trades on-chain.
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract SecureLending {
AggregatorV3Interface internal priceFeed;
constructor(address _priceFeed) {
priceFeed = AggregatorV3Interface(_priceFeed);
}
function getLatestPrice() public view returns (int) {
(
uint80 roundID,
int price,
uint startedAt,
uint timeStamp,
uint80 answeredInRound
) = priceFeed.latestRoundData();
require(timeStamp > 0, "Round not complete");
return price;
}
}
Avantages :
- Données agrégées de multiples sources
- Mis à jour off-chain (non manipulable via flash loans)
- Battle-tested sur des milliards en TVL
3. Gouvernance par Snapshot
Pour les DAOs, utilisez des snapshots basés sur les blocs pris avant le début du vote.
contract SecureGovernance {
mapping(uint256 => uint256) public proposalSnapshots;
function propose(/*...*/) external returns (uint256) {
uint256 proposalId = proposalCount++;
// Snapshot AVANT le début du vote
proposalSnapshots[proposalId] = block.number;
return proposalId;
}
function vote(uint256 proposalId, bool support) external {
// Utiliser le solde au bloc du snapshot
uint256 votes = govToken.balanceOfAt(
msg.sender,
proposalSnapshots[proposalId]
);
// Les flash loans après création de proposition ne comptent pas
}
}
4. Délais d'Exécution
Ajouter des timelocks pour empêcher l'exécution instantanée.
contract TimelockDAO {
uint256 public constant DELAY = 2 days;
struct Proposal {
uint256 eta; // Temps d'exécution le plus tôt
// ...
}
function queue(uint256 proposalId) external {
require(proposalPassed(proposalId));
proposals[proposalId].eta = block.timestamp + DELAY;
}
function execute(uint256 proposalId) external {
require(block.timestamp >= proposals[proposalId].eta);
// Exécuter
}
}
Les flash loans doivent être remboursés en une transaction, donc ils ne peuvent pas attendre 2 jours.
5. Détection de Flash Loan
Bloquer l'utilisation de flash loan pour les fonctions sensibles.
contract FlashLoanProtected {
mapping(address => uint256) private balanceSnapshot;
modifier noFlashLoan() {
uint256 balanceBefore = balanceSnapshot[msg.sender];
// Première interaction dans cette transaction
if (balanceBefore == 0) {
balanceSnapshot[msg.sender] = token.balanceOf(msg.sender);
} else {
// Le solde ne devrait pas spike dans la même transaction
require(
token.balanceOf(msg.sender) <= balanceBefore * 2,
"Flash loan detected"
);
}
_;
}
function sensitiveAction() external noFlashLoan {
// Protégé
}
}
Note : Ceci peut avoir des faux positifs, utiliser avec précaution.
Résumé des Bonnes Pratiques
Pour les Protocoles de Prêt
✅ Utiliser Chainlink ou oracles TWAP, jamais les prix spot
✅ Implémenter des vérifications de santé sur les changements de prix
✅ Ajouter des circuit breakers pour conditions de marché anormales
✅ Nécessiter des délais multi-blocs pour les changements de position importants
Pour les DAOs
✅ Snapshot des soldes à la création de proposition
✅ Ajouter des timelocks (minimum 24-48 heures)
✅ Nécessiter un quorum de holders long-terme
✅ Utiliser la délégation de vote pour empêcher les attaques de gouvernance de dernière minute
Pour Tous les Protocoles DeFi
✅ Auditer toutes les dépendances de prix
✅ Tester avec des scénarios d'attaque par flash loan
✅ Monitorer les patterns de transaction inhabituels
✅ Avoir des mécanismes de pause d'urgence
✅ Maintenir des programmes de bug bounty
Conclusion
Les flash loans sont une primitive DeFi puissante qui démocratise l'accès au capital — mais ils démocratisent aussi l'accès aux exploits.
Les attaques ne sont pas causées par les flash loans eux-mêmes, mais par des vulnérabilités sous-jacentes que les flash loans amplifient :
- Oracles faibles (utiliser TWAP ou Chainlink)
- Gouvernance instantanée (ajouter snapshots et timelocks)
- Réentrance (utiliser des guards)
- Liquidations non protégées (ajouter des délais)
Le bottom line : Si votre protocole peut être exploité avec assez de capital, supposez que quelqu'un va flash loan ce capital.
Pratiquez la défense contre les flash loans sur Solingo — nos exercices simulent des attaques réelles incluant manipulation d'oracle et prises de contrôle de gouvernance, avec implémentation de défense étape par étape.