Les checklists de sécurité Solidity ne manquent pas. Le SWC Registry, l'OWASP Smart Contract Top 10, les bonnes pratiques ConsenSys, la doc OpenZeppelin, les guides Trail of Bits, Secureum, Sigma Prime. Ils sont tous bons. Ils sont aussi fragmentés, et la plupart décrivent le bug sans vous dire lequel de ces bugs a réellement vidé une trésorerie le trimestre dernier.
Nous avons donc fait la fusion. Nous avons pris les 78 incidents de notre propre flux de menaces Web3 — chacun une perte réelle, sourcée, analysée en post-mortem — et les avons alignés sur les guides de référence. Cet article en est le résultat : une liste unique de ce qu'il faut vérifier pour sécuriser du code Solidity, avec les vrais hacks qui prouvent chaque point et le correctif concret. Lisez-la une fois et vous avez la carte.
Lisez d'abord les données : l'argent est passé du code aux clés
Avant la checklist, le glissement le plus important à comprendre. Les vulnérabilités qui définissent la sécurité Solidity dans les tutoriels — réentrance, jeux d'oracle via flash loan — ne sont plus là où va l'essentiel de l'argent.
- Les défaillances de contrôle d'accès et de compromission de clés sont désormais la première cause de vol de crypto en dollars. L'OWASP classe le contrôle d'accès n°1 de son Smart Contract Top 10 2025, lui attribuant environ 953 M$ de pertes en 2024. Chainalysis situe la compromission de clés privées à ~44 % de tous les fonds volés en 2024. Ce sont des incidents rares à la sévérité moyenne énorme.
- Les bugs de contrat classiques sont en grande partie résolus. Les données sur six ans d'Immunefi montrent les attaques par flash loan chutant de 54 % des pertes DeFi en 2020 à moins de 1 % en 2025, et la réentrance suivant la même courbe. De meilleurs outils, des bibliothèques auditées et Solidity 0.8 ont fait leur travail.
- Quelques méga-incidents portent les totaux. Bybit (~1,5 Md$, fév. 2025) représentait à lui seul ~44 % de toute la valeur volée de l'année, et ce n'était pas un bug Solidity — c'était un workflow de signature compromis. Ronin (625 M$), c'étaient des clés de validateurs hameçonnées par spear-phishing. Poly Network (611 M$), une faille de fonction privilégiée.
- Le risque de code résiduel, c'est votre propre logique métier. Les patterns génériques étant traités, la longue traîne qui reste est la comptabilité et la logique spécifiques à l'application — les bugs qu'aucune checklist ne peut énumérer parce qu'ils n'existent que dans votre protocole.
Ce qu'il faut retenir pour répartir l'effort : ne livrez pas les bugs classiques (ils sont peu coûteux à éviter et toujours fatals la seule fois où vous les manquez), durcissez la frontière de confiance autour du code (c'est par là que l'essentiel de l'argent part réellement), et testez par invariants votre propre logique (c'est la frontière). La checklist ci-dessous est ordonnée dans cet esprit.
1. Contrôle d'accès et fonctions privilégiées
La première cause en dollars. Toute fonction qui peut déplacer des fonds, minter, mettre en pause, mettre à niveau ou changer un paramètre est une fonction privilégiée, et chacune a besoin d'un contrôle d'autorisation explicite et correct.
Ce qui dérape, preuves à l'appui :
- Un contrôle manquant ou erroné. Poly Network laissait le gestionnaire cross-chain appeler un setter de keeper privilégié qu'il possédait justement ; l'attaquant a forcé par brute-force un nom de fonction dont le sélecteur 4 octets entrait en collision avec lui et a remplacé toutes les clés du bridge. 611 M$.
- Une clé sur-privilégiée ou dormante. Gala Games avait un rôle
MINTERcorrect — la défaillance était un compte de minter compromis et dormant qui a minté 5 Md de tokens. PlayDapp avait la même forme : une clé de déployeur hameçonnée appelantaddMinter. tx.originpour l'authentification. Un contrat qui vérifierequire(tx.origin == owner)peut être hameçonné via un contrat intermédiaire malveillant — voir la classe tx.origin.- Un setter privilégié non protégé. Un setter de prix ou de taux laissé atteignable est le même bug qu'un mint ouvert. KiloEx (~7,5 M$ sur quatre chaînes, avr. 2025) a exposé son
setPricesd'oracle via un forwarder de méta-transaction publiquement appelable, si bien que l'attaquant a écrit un prix arbitraire et a tradé contre. Vow n'avait pas de timelock sur son setter de taux USD, donc quand un admin a brièvement basculé le taux à 100× « pour tester », un bot MEV a minté ~148 M de vUSD en deux blocs.
Ce qu'il faut vérifier / comment corriger (SWC-105, SWC-106, SWC-115 ; OWASP SC01:2025) :
- Autorisez sur
msg.sender, jamaistx.origin. - Utilisez des primitives auditées :
Ownable/AccessControl(basé sur les rôles) d'OpenZeppelin, etOwnable2Steppour qu'un transfert de propriété maladroit ne puisse pas bloquer le contrat. - Mettez les actions dangereuses — mint, mise à niveau,
selfdestruct, changements de paramètres — derrière un multisig et un timelock, pas un EOA unique. Appliquez le moindre privilège : le moins de rôles possible, détenus par le moins de clés possible. - Ajoutez de la surveillance et un chemin de pause testé pour qu'un privilège abusé soit attrapé en minutes, pas en jours.
2. Initialisation et mises à niveau de proxy
Les contrats à mise à niveau ajoutent deux modes de défaillance que les contrats plats n'ont pas, et les deux ont drainé des montants à neuf chiffres.
- Initialiseur non protégé / ré-appelable. Dans un proxy, le constructeur du contrat de logique ne s'exécute jamais dans le contexte du proxy, donc l'initialisation passe à une fonction
initialize()— et si cette fonction est appelable une deuxième fois, un attaquant l'appelle pour s'emparer de la propriété. Le gel original du wallet Parity était exactement cela : uninitWalletnon protégé sur une bibliothèque partagée, suivi d'unselfdestruct. - Collision de disposition de stockage (storage layout). Un proxy delegatecall exécute la logique contre le stockage du proxy, donc les deux doivent s'accorder sur chaque slot. Audius a ajouté une variable de proxy qui entrait en collision avec le drapeau
initializedde l'implémentation, rouvrant l'initialiseur et laissant un attaquant passer une proposition de gouvernance malveillante. Munchables était un initié malveillant pré-amorçant le stockage qui a survécu à la mise à niveau.
Ce qu'il faut vérifier / comment corriger (SWC-118 ; OWASP 2026 Proxy/Upgradeability ; OpenZeppelin Upgrades) :
// Verrouille l'implémentation pour que son initialiseur ne puisse jamais être appelé sur le contrat de logique lui-même.
constructor() {
_disableInitializers();
}
function initialize(address owner_) external initializer { // OZ Initializable : s'exécute exactement une fois
__Ownable_init(owner_);
}
- Protégez chaque initialiseur avec
Initializabled'OpenZeppelin (initializer/reinitializer) et appelez_disableInitializers()dans le constructeur de l'implémentation. - Préservez la disposition du stockage à travers les mises à niveau : variables en ajout seul, storage gaps ou stockage namespacé ERC-7201, et lancez un diff automatisé de la disposition du stockage (
openzeppelin-upgrades) à chaque mise à niveau. - Ne mettez jamais de
selfdestructni dedelegatecallnon fiable dans un contrat à mise à niveau.
3. Réentrance (les quatre types)
Le plus vieux bug du manuel, et toujours d'actualité car il a engendré des variantes. La règle tient en une phrase : terminez tous vos changements d'état avant de faire un appel externe.
- Classique — The DAO envoyait de l'ether avant de remettre le solde à zéro ; le fallback du destinataire ré-entrait et retirait à répétition.
- Réentrance par token à callback / ERC-777 — dForce / Lendf.me et Grim Finance : un transfert de token déclenche un hook vers le code de l'attaquant en plein milieu d'une mise à jour.
- Inter-fonctions / inter-contrats — Rari / Fei ré-entrait dans le
exitMarketdu Comptroller depuis un transfert CEther ; une protection à fonction unique n'aurait pas aidé. Penpie ré-entrait dans une fonction différente qui partageait un verrou que celle protégée n'avait pas. - Réentrance en lecture seule (read-only) — Conic : un
viewnon protégé utilisé comme source de prix renvoyait une valeur corrompue pendant qu'un pool Curve était en pleinremove_liquidity.
Ce qu'il faut vérifier / comment corriger (SWC-107 ; OWASP SC05:2025 ; ConsenSys ; ReentrancyGuard d'OZ) :
function withdraw(uint256 amount) external nonReentrant {
require(balances[msg.sender] >= amount, "insufficient");
balances[msg.sender] -= amount; // les effets d'abord
(bool ok, ) = msg.sender.call{value: amount}(""); // l'interaction en dernier
require(ok, "transfer failed");
}
- Appliquez checks-effects-interactions partout, et un mutex
nonReentrantsur les points d'entrée qui changent l'état — la protection doit couvrir toutes les fonctions qui partagent l'état, pas une seule. - Traitez les hooks de transfert ERC-777/677/1363 comme des points de réentrée non fiables ; préférez les retraits en pull plutôt qu'en push.
- Avant de lire un
viewexterne comme oracle, déclenchez d'abord le propre verrou de réentrance de la source.
4. Manipulation d'oracle et de prix (et flash loans)
Si votre contrat lit un prix, posez une seule question : quelqu'un peut-il déplacer ce prix dans la même transaction ? Si la réponse est oui, ce n'est pas un oracle, c'est une surface d'attaque. Les flash loans rendent la réponse oui pour presque n'importe quel prix spot à pool unique.
- Prix spot d'un pool unique — bZx (le premier célèbre), Harvest, PancakeBunny, Cream : un flash loan déséquilibre un pool Uniswap/Curve, le protocole lit
getReserves()/balanceOf(), et surévalue le collatéral de l'attaquant. - Une fenêtre TWAP manipulable — Inverse Finance : un TWAP dont la porte de mise à jour retombait sur le prix spot d'un pool peu profond.
- Un feed maison lisant l'état brut d'un AMM — UwU Lend : un oracle prenant la médiane de lectures spot de pool, et Mango : un PnL de perp valorisé sur un marché spot peu profond.
Ce qu'il faut vérifier / comment corriger (OWASP SC02 & SC07:2025 ; ConsenSys Oracle Manipulation) :
- Valorisez les actifs avec un oracle résistant à la manipulation — agrégation Chainlink, une médiane de sources indépendantes, ou un TWAP sur une fenêtre suffisamment longue. Jamais le spot
getReserves(),balanceOf()ouget_p()d'un pool unique. - Vérifiez la péremption/heartbeat de l'oracle et bornez la déviation ; rejetez les prix lus dans un appel atomique de flash loan.
- Plafonnez la part de valeur non réalisée/volatile qui peut compter comme collatéral, et stress-testez chaque lecture de prix contre un attaquant qui contrôle le pool pendant un bloc.
5. Arithmétique : dépassement, arrondi et invariants d'AMM
Trois modes de défaillance distincts qui se réduisent tous à « le calcul était faux ».
- Dépassement (overflow/underflow). Avant la 0.8, c'était endémique — la multiplication de
batchTransferde BEC repassait à zéro et franchissait la vérification de solde. Cela arrive encore dans les blocsuncheckedet les VM non-Solidity : Cetus (un masque d'overflow erroné dans une bibliothèque Move, 223 M$) et Velocore (un terme de frais qui a sous-dépassé et repassé en boucle). - Arrondi / précision et l'attaque par inflation ERC-4626. La division entière tronque. L'attaque du premier déposant / par donation l'arme : amorcer un coffre (vault) vide avec 1 wei, donner pour gonfler le prix par part, et les déposants suivants arrondissent à zéro part. Pertes réelles : Sonne, Onyx, zkLend — toutes des manipulations de taux de change sur marché vide. Et les bugs d'arrondi ne se limitent pas aux coffres : Bunni (~8,4 M$, sept. 2025) a arrondi un « solde inactif » dans le mauvais sens sur son chemin de retrait Uniswap-v4, et une séquence de swaps financée par flash loan à travers des frontières de tick a déclenché l'erreur jusqu'à ce que le pool fuie — après quoi le protocole a fermé.
- Invariants d'AMM / de comptabilité cassés. Uranium a livré un invariant
kavec un10000là où1000allait ; Spartan calculait le paiement LP depuis lebalanceOfen direct au lieu des réserves en cache ; KyberSwap comptait deux fois la liquidité à une frontière de tick exacte.
Ce qu'il faut vérifier / comment corriger (SWC-101 ; OWASP SC08:2025) :
- Utilisez l'arithmétique vérifiée de Solidity ≥ 0.8 ; ne recourez à
unchecked{}que là où le dépassement est prouvablement impossible. Sur les VM non-EVM, vérifiez vous-même le comportement de dépassement de la bibliothèque mathématique. - Multipliez avant de diviser ; ne supposez jamais 18 décimales ; arrondissez en faveur du protocole et rejetez les mints à zéro part.
- Défendez les coffres avec des parts virtuelles / un décalage de décimales (OZ ERC4626) ou un dépôt initial amorcé par le protocole ; suivez les soldes avec une comptabilité interne, jamais un
balanceOfbrut qu'une donation peut gonfler. - Testez en unité et par invariants chaque formule de frais, de part et de réserve aux entrées limites.
6. Appels externes, retours non vérifiés et approbations
L'EVM ne lève pas d'exception quand un appel bas niveau échoue — il renvoie false. Ignorez cela et vous traitez un transfert échoué comme un succès.
- Valeur de retour non vérifiée — le bug canonique King of the Ether : un
send()a renvoyéfalse, le code l'a ignoré, et l'état a avancé quand même. - Appel externe arbitraire avec cible/calldata contrôlées par l'attaquant — Li.Fi et Hedgey laissaient les appelants passer une cible que le contrat
callait ensuite, armant les propres approbations du routeur pour exécutertransferFromcontre les victimes. - Confiance non validée en une adresse fournie — Pickle acceptait un faux « jar » avec la bonne interface.
Ce qu'il faut vérifier / comment corriger (SWC-104, SWC-124 ; OWASP SC06:2025 ; SafeERC20/Address d'OZ) :
- Vérifiez chaque valeur de retour. Enveloppez les appels de tokens dans
SafeERC20; enveloppez les appels bruts dansAddress.functionCall. - Mettez en allowlist les cibles d'appel et les sélecteurs. Ne laissez jamais un utilisateur fournir un
target+calldataarbitraire qui s'exécute avec les permissions de votre contrat, et ne laissez jamais lefromd'untransferFromêtre choisi par l'attaquant. - La conformité d'interface n'est pas de la confiance — validez les adresses contre un registre des contrats que vous avez déployés.
7. Signatures, rejeu et vérification de preuves
Partout où vous vérifiez une signature ou une preuve hors du chemin heureux, ce sont les détails qui décident si c'est sécurisé.
- Preuves forgées / sous-vérifiées — Wormhole faisait confiance à un compte fourni par l'appelant au lieu de le vérifier contre le vrai sysvar ; BNB Chain acceptait une preuve Merkle IAVL malformée. Les deux ont minté des actifs non adossés.
- Réutilisation de signature/nonce — AnySwap a réutilisé un nonce ECDSA sur deux transactions, fuitant la clé privée.
- Rejeu cross-chain / contexte manquant — la classe de rejeu de signature : une signature valide une fois, rejouée parce qu'elle ne portait ni chainId, ni nonce, ni domaine.
Ce qu'il faut vérifier / comment corriger (SWC-117, SWC-121, SWC-122 ; ECDSA d'OZ) :
- Liez chaque message signé avec des données typées EIP-712 + un séparateur de domaine (name, version, chainId, verifyingContract) + un nonce par signataire, et marquez les signatures à usage unique.
- Imposez un
sbas (low-s) et unvvalide, et rejetezaddress(0)deecrecover(utilisezECDSAd'OZ). - Vérifiez les preuves et les comptes externes par adresse/structure, pas par position ou forme ; fuzzez le vérificateur contre des entrées malformées.
8. Gouvernance
Si le pouvoir de vote peut être acquis et utilisé dans la même transaction, la gouvernance est à un flash loan de vous appartenir. Beanstalk a perdu 182 M$ quand un attaquant a emprunté en flash une supermajorité de votes et exécuté une proposition malveillante en une transaction.
- Capturez le pouvoir de vote à un bloc passé (ERC20Votes / checkpoints), pour qu'il ne puisse pas être emprunté en flash.
- Mettez un timelock entre proposition, vote et exécution, et interdisez aux chemins d'urgence d'appeler des contrats arbitraires qui déplacent des fonds.
9. Au-delà du code : la frontière de confiance qui perd réellement l'argent
C'est la moitié inconfortable de la méta-analyse. Les plus grosses pertes de notre flux ne sont pas du tout des bugs Solidity — c'est l'infrastructure autour d'un contrat parfaitement sain. Si vous livrez un protocole impeccable derrière un signataire compromis, vous avez le pattern Bybit.
- Signature à l'aveugle (blind-signing) en multisig. Bybit (~1,5 Md$), Radiant et WazirX se résument tous à des signataires de wallet matériel approuvant un
delegatecalldont leur appareil n'affichait pas le véritable effet. Imposez le clear-signing, la vérification du calldata sur l'appareil et la simulation indépendante des transactions. Ne signez jamais à l'aveugle. - Compromission du frontend / de la supply-chain. BadgerDAO (prompts d'approbation injectés) et Ledger Connect Kit (un paquet npm empoisonné qui a drainé des dizaines de dApps d'un coup) n'ont jamais touché les contrats. Ce n'est pas un cas isolé — c'est le goutte-à-goutte régulier que les données font sans cesse remonter. La vague de détournement DNS a pris le domaine de Curve deux fois (2022, puis de nouveau en mai 2025, forçant le passage à
curve.finance), a redirigé Compound lors de l'effondrement du registrar Squarespace de juillet 2024, a touché Ambient, et en avril 2026 a drainé plus de 1 M$ aux utilisateurs de CoW Swap (219 ETH d'un seul wallet) après que des documents forgés ont trompé son registrar pour qu'il cèdecow.fi— chacune en repointant un domaine, jamais un contrat. Et en septembre 2025, une compromission npm unique dechalk/debug(2 Md+ de téléchargements hebdomadaires) a livré un clipper crypto échangeur d'adresses de wallet à tout ce qui se construisait dessus. Utilisez la Subresource Integrity, des dépendances épinglées, des releases signées, le verrouillage du registrar/registre + DNSSEC + 2FA par clé matérielle, et envisagez un hébergement adressé par contenu (ENS/IPFS). - Le compilateur fait partie de votre frontière de confiance. Curve / Vyper : une version spécifique du compilateur générait mal le verrou de réentrance. Épinglez et vérifiez votre version de compilateur et reconstruisez le bytecode déployé depuis une source auditée.
- Protégez vos utilisateurs du phishing d'approbation. Les kits de drainer, le phishing de signature permit, les approbations illimitées et l'empoisonnement d'adresse sont là où le retail perd (~494 M$ en 2024, dont les signatures
permità elles seules 57 %). Demandez des approbations au montant exact et au moindre privilège, supportez la révocation, et affichez l'intention de transaction lisible par un humain dans votre interface.
10. Comment trouver les bugs qu'aucune liste ne peut nommer
Tout ce qui précède dit quoi chercher. Mais le risque résiduel — la logique spécifique à l'application qui domine désormais les pertes — n'a aucune entrée dans aucun registre, car il n'existe que dans votre protocole. On ne peut pas faire correspondre par pattern un bug jamais vu. On le trouve par la façon dont on lit le code, pas par la liste qu'on tient. La discipline qui fait émerger ces bugs est un seul geste répété : lire le code plusieurs fois, chaque passe avec un seul état d'esprit, et faire confiance à votre malaise plutôt qu'à votre première lecture.
Trois outils pour lire une fonction honnêtement. L'avantage de l'auditeur senior n'est pas de connaître plus de patterns ; c'est de lire sans faire confiance à sa première lecture.
- Feynman. Expliquez ce que fait la fonction en français clair, sans mot Solidity. À l'instant où vous recourez au jargon — « elle
safeTransfere les frais » au lieu de « elle prélève la part du protocole sur le paiement de l'utilisateur et la déplace vers la trésorerie » — vous avez masqué une hypothèse. C'est là qu'est le bug. - Socratique. Pour chaque ligne, demandez : pourquoi est-ce là, qu'est-ce que cela suppose, qu'est-ce qui casse si l'hypothèse est fausse ? Creusez au-delà de la reformulation.
if (token != ETH) transferFrom(...)— pourquoi pas deelse? Parce qu'on suppose que l'ETH arrive viamsg.value. Oùmsg.value == amountest-il imposé ? Si la réponse est « nulle part », vous le tenez. - Inversion. Chaque chemin propre subit une passe à rebours. Le développeur demande « est-ce que ça marche ? » ; vous demandez « comment faire pour que ça ne marche pas ? ». Lisez chaque vérification et demandez quelle valeur lui échappe ; lisez chaque mise à jour d'état et demandez dans quel état vous êtes juste avant qu'elle ne se déclenche.
Puis lisez le même code sous différentes lentilles — les bugs vivent aux coutures. Une seule classe de bug raconte rarement toute l'histoire ; les coûteux se logent là où deux vues se chevauchent :
- Asymétrie. Les opérations appariées doivent se refléter : dépôt/retrait, mint/burn, lock/unlock, la branche native vs ERC-20. Le bug n'est pas une ligne erronée — c'est la mise à jour qu'un côté fait et que l'autre a oubliée. (C'est la forme Penpie de la section 3 et la forme arrondi de la section 5.)
- Invariants. Écrivez ce qui doit toujours être vrai — le total des parts adosse le total des actifs, la somme des soldes égale le pool, la dette n'arrondit jamais en faveur de l'utilisateur — puis traquez le chemin qui le viole et extrayez de la valeur de l'état cassé.
- Frontières. Appliquez les mêmes questions de cas limites à chaque entrée et site d'appel : zéro, un, vide, max, première fois, le montant poussière, l'adresse auto-référentielle.
- Périphérie. La bibliothèque, le helper ou l'encodeur de 20 lignes non relu auquel les contrats cœur font implicitement confiance. Un seul bug là compromet chaque appelant — Cetus et Velocore (section 5) étaient tous deux des maths de bibliothèque.
- Interstices (gaps). Les bugs les plus durs exigent deux ou trois lentilles à la fois : une erreur d'arrondi (précision) qui ne casse une loi de conservation (invariant) qu'à un pool vide (frontière). Aucun scan mono-classe ne le voit ; relisez les coutures à dessein.
Et calibrez ce qui compte comme un finding — c'est la différence entre un audit et une impression :
- Un finding n'est pas réel tant que vous n'avez pas tracé l'attaque avec des valeurs concrètes — un nombre, une séquence d'états, une ligne citée. Sans preuve, c'est une piste, pas un finding. Les pistes sont honnêtes, pas des échecs ; notez-les pour suivi au lieu de les laisser tomber.
- Quand vous trouvez un bug, approfondissez-le — ne vous en dissuadez jamais. Chaînez-le, trouvez plus de victimes, abaissez le coût de la précondition.
- Armez chaque bug à travers tout le code. Confusion native/ERC-20 dans un
onRevert? Vérifiez leonRevertde chaque contrat. La même erreur est presque toujours copiée-collée. - Filtrez honnêtement. Une protection interrompt-elle réellement l'attaque avant le dommage ? Un acteur non privilégié peut-il atteindre l'état vulnérable et le déclencher ? Le dommage est-il matériel pour une vraie victime ? « L'admin peut rug » sans amplificateur non privilégié n'est pas un finding.
Comment l'appliquer concrètement
Une liste n'est utile que si elle s'exécute en continu. Les pratiques qui font bouger l'aiguille :
- Relisez en lentilles, pas en une passe — la contrepartie manuelle de la section ci-dessus : balayez le code une fois par état d'esprit (asymétrie, invariants, frontières, périphérie, les coutures), parce qu'une lecture unique tenant toutes les classes de bugs à la fois est le scan de surface qui manque les bugs de logique.
- Bâtissez sur des bibliothèques auditées (OpenZeppelin) et le dernier compilateur stable, épinglé — vous héritez gratuitement des gardes de réentrance, des maths sûres et du contrôle d'accès.
- Analyse statique en CI — Slither et Mythril sur chaque PR, filtrant les détecteurs à confiance haute et moyenne.
- Fuzzing et tests par invariants — Foundry / Echidna contre vos invariants comptables spécifiques au protocole. C'est la seule chose qui attrape les bugs de logique de longue traîne qui dominent désormais le risque résiduel.
- Défense en profondeur — disjoncteurs (pausable), limites de débit de retrait et timelocks sur les actions admin, pour qu'une seule erreur soit survivable.
- Audits indépendants, surveillance, un bug bounty et un plan de réponse aux incidents — et un environnement de signature durci et segmenté, parce que les données disent que c'est par là que va l'argent.
Rien de tout cela n'est nouveau. Ce qui est nouveau, c'est de l'avoir au même endroit, classé par ce qui cause réellement la perte, et lié aux incidents précis qui prouvent chaque point — ce qui est tout l'intérêt de tenir un flux de menaces en premier lieu.
C'est aussi pour cela que j'ai conçu Stateward pour raisonner sur le code entier plutôt que sur un seul diff. La plupart des classes ci-dessus — une garde de réentrance qui ne couvre pas une fonction sœur, une lecture d'oracle sûre jusqu'à ce qu'un nouveau chemin d'emprunt l'atteigne, un initialiseur laissé ouvert après un refactor — sont des propriétés de la façon dont les pièces s'assemblent, pas d'une seule ligne. Un relecteur qui comprend le système les attrape. Un scanner qui lit une ligne, non. Et chaque dépendance que vous tirez est vérifiée contre ce même flux d'exploits réels, à chaque pull request.