Failles logique métier (CWE-840) : détourner des fonctionnalités valides — manipulation de prix, contournement de workflow, empilement de coupons invisibles aux scanners.
TL;DR
price=0.01 n'est un bug que si le serveur l'accepte.SELECT FOR UPDATE), clés d'idempotence et machine à états stricte.La plupart des classes de vulnérabilités ont un signe distinctif. L'injection SQL laisse une erreur de syntaxe dans une stack trace. Le XSS reflété renvoie un payload dans le DOM. Un broken access control déclenche un HTTP 403 qui devient soudain un 200. Un scanner peut sonder n'importe lequel de ces cas parce que le bug a une signature — une chaîne, un motif, un changement d'état lié à une forme connue d'entrée. Les failles de logique métier n'ont rien de tout cela. La requête HTTP paraît identique à une requête que l'application reçoit mille fois par heure de la part de clients honnêtes. Le payload est du JSON bien formé, la session est authentifiée, la route est une que le développeur a écrite intentionnellement. Il n'y a rien à grepper.
Ce qui change, c'est l'intention. L'application a été conçue en supposant qu'un checkout visiterait /cart, /address, /payment, /confirm dans cet ordre, une fois chacun. Que quantity serait positif et qu'un coupon SAVE10 serait appliqué au plus une fois par commande. Que deux personnes ne pourraient pas utiliser la même carte cadeau à usage unique dans la même fenêtre de cinq millisecondes. Aucune de ces hypothèses n'est écrite dans le schéma de la requête, la spec OpenAPI ou le ruleset WAF — elles vivent dans la tête du développeur, et c'est précisément là que les attaquants vont chercher. CWE-840 (Business Logic Errors) et CWE-841 (Improper Enforcement of Behavioral Workflow) couvrent le territoire, et le nouveau OWASP Top 10 for Business Logic Abuse 2025 donne enfin à cette classe la taxonomie dédiée dont elle avait besoin depuis une décennie. La mise à jour OWASP Top 10:2025 renomme cette catégorie A06:2025 — Insecure Design et l'élève aux côtés du nouveau OWASP Top 10 for Business Logic Abuse 2025 dédié.
C'est pourquoi le test de logique métier exige une mentalité différente du reste de l'OWASP Top 10. Vous ne pouvez pas détecter une faille que vous ne comprenez pas. Avant de pouvoir casser un checkout, vous devez savoir à quoi ressemble un checkout honnête — quel état le serveur suit, quels champs le client contrôle, quels garde-fous ont été ajoutés et lesquels ont été oubliés. C'est pourquoi ces bugs paient les plus hautes bounties sur HackerOne (25K$-150K$ chez Shopify, jusqu'à 500K$ critical ailleurs) : l'écart entre le scan commodity et le test manuel d'élite est ici à son maximum.
En juin 2023, un chercheur a rapporté HackerOne #1849626 à Stripe. La faille était presque embarrassante de simplicité. L'API de codes promotionnels de Stripe accepte un paramètre max_redemptions que les marchands utilisent pour plafonner le nombre d'utilisations d'un code — généralement 1 pour les codes promo à usage unique. L'endpoint de redemption fait la vérification séquentielle évidente : charger le code, compter les redemptions, accepter si count < max_redemptions, incrémenter, committer. Cinq lignes de code, exécutées des millions de fois par jour. La vérification fonctionne parfaitement quand les requêtes arrivent une à la fois.
Voici ce que le chercheur a fait :
max_redemptions=1, observation de la requête de redemption normale, capture du JWT et du body. Un scanner voit un POST. L'attaquant voit la vérification et l'utilisation — deux opérations séparées par une minuscule fenêtre de race.count < 1 avant qu'aucune n'ait eu la chance d'incrémenter le compteur.Un scanner DAST tournant contre le même endpoint aurait envoyé un POST, obtenu un 200, et serait passé à autre chose. Aucun payload à fuzzer, aucun en-tête à injecter, aucun paramètre suspect. Chaque requête individuelle était valide selon la sémantique propre de Stripe. Le bug n'existe qu'à l'intersection d'un endpoint qui modifie l'état, d'une garantie de concurrence que le développeur a supposée mais jamais imposée, et d'un attaquant prêt à envoyer 30 requêtes d'un coup. C'est la texture de toute la classe.
La même primitive — requêtes concurrentes contre une ressource à usage unique — réapparaît sans cesse. Instacart HackerOne #157996 (empilement de coupons), Reverb HackerOne #759247 (redemption de carte cadeau), Dropbox HackerOne #59179 (code promo Pro) et Tesla 2020 (logiciel véhicule payant) sont toutes des variantes de la même race condition. Une fois que vous reconnaissez la forme, vous la trouvez partout.
Les failles de logique métier couvrent des dizaines de motifs nommés, mais la bibliothèque /learn de BreachVex les organise autour des six classes qui dominent les rapports de bounty réels. Chacune a son propre deep dive avec payloads, logique de détection et patterns de remédiation.
Le serveur fait confiance à un champ price fourni par le client au lieu de recalculer le coût depuis un catalogue côté serveur. Envoyer {"product_id": 123, "price": 0.01} contre un produit à 99,99$ est l'exemple canonique, démontré dans le lab "Excessive Trust in Client-Side Controls" de PortSwigger et dans HackerOne #614523 (Eternal). Les variantes incluent le replay de prix archivé (Stripe HackerOne #1328278) et le changement de devise. Deep dive : Manipulation de prix
Le serveur accepte quantity=-5, amount=-1000 ou des numériques signés qui inversent le signe d'un total de commande ou d'un transfert. CVE-2023-45854 (Shopkit 1.0, CVSS 7.5) faisait passer qtd=2147483648 au-delà d'INT32_MAX en territoire négatif, et HackerOne #364843 (Upserve/OLO) acceptait des lignes négatives qui ramenaient le total de la commande à zéro. Deep dive : Abus de quantité négative
La vérification de déduplication ne regarde que le coupon immédiatement précédent, pas l'historique complet d'application. Le lab "Flawed Enforcement of Business Rules" de PortSwigger démontre le pattern alterné ABA : SAVE10, puis WELCOME5, puis SAVE10 à nouveau — le second SAVE10 accepté. La variante "infinite money" enchaîne une remise avec une carte cadeau remboursable. Bounty : HackerOne #157996 (Instacart). Deep dive : Empilement de coupons
POST direct vers /checkout/confirm depuis une session fraîche, en sautant /cart, /address et /payment. L'application n'impose pas l'ordre des étapes côté serveur, s'appuyant souvent sur un champ caché de formulaire ou un état SPA côté client. HackerOne #271176 (Lyst), HackerOne #92481 (Shopify) et Magento2 issue #39145 ont tous frappé des variantes. Deep dive : Contournement d'étape de workflow
Plafonds par utilisateur, par jour ou par compte qui existent côté client mais ne sont pas imposés côté serveur — ou imposés de manière séquentielle d'une façon que les requêtes concurrentes brisent. Spam SMS via OTP répétés, contournement de quota d'API en tier gratuit, réactivation de période d'essai en recréant le compte. La famille function_use_limit dans le guide de test OWASP. Deep dive : Dépassement de limite
L'arithmétique flottante et l'arrondi par ligne permettent aux attaquants de gratter des fractions de centime sur des centaines d'articles, ou de gonfler des remboursements via un arrondi inverse. Dévastateur en fintech et sur les contextes d'échange crypto, où un avantage de 0,001$ multiplié par le volume de transactions devient de l'argent réel. Deep dive : Abus d'arrondi monétaire
Tous les scanners DAST traditionnels — ZAP, Burp Scanner, Nuclei, Acunetix, Netsparker — fonctionnent fondamentalement de la même manière : crawler l'application, lister les endpoints, rejouer chacun avec des payloads de fuzzing, et surveiller la réponse pour une signature connue. Ce modèle est excellent pour l'injection SQL (SQL syntax error), le XSS (canari dans le DOM), le SSRF (hit DNS OOB sur Burp Collaborator). Il est structurellement incapable de trouver les failles de logique métier — pas à cause d'un bug ou d'une fonctionnalité manquante, mais parce que les exploits de logique métier ne sont pas des entrées malformées, ce sont des séquences bien formées. Le scanner n'a pas d'hypothèse à tester.
Trois éléments aggravent le problème. La preuve exige une vérification d'état : confirmer que "le transfert négatif a crédité le compte" signifie lire le solde avant et après, ce qui exige de tracker un état spécifique à l'application à travers des requêtes que le scanner ne modélise pas. Les workflows multi-étapes exigent couramment 3-10 requêtes coordonnées dans un ordre spécifique avec des données spécifiques, et le fuzzing de requête unique ne peut pas les reproduire. Les race conditions sont dépendantes du timing : la détection exige des single-packet attacks HTTP/2 plutôt que des requêtes séquentielles, ce que la plupart des scanners commerciaux n'implémentent toujours pas.
Une nouvelle génération d'outils a commencé à combler le fossé. Pynt rejoue le trafic API capturé avec des mutations. Escape fait tourner un moteur piloté par feedback qu'ils appellent BLST (Business Logic Security Testing). Le module BLT de StackHawk sort en 2025 avec des ambitions similaires, et AppCheck utilise GoScript Flows pour modéliser des parcours utilisateurs multi-étapes. Les quatre représentent un vrai progrès, et les quatre nécessitent toujours une configuration humaine significative. Le résumé honnête, c'est que la détection de logique métier en 2026 se trouve là où le DAST se trouvait en 2008 : pratique pour quelques motifs bien connus, inutile pour la longue traîne. Le moteur de logique métier de BreachVex se situe à la même frontière — compétent sur les classes nommées, dépendant d'un moteur de règles YAML personnalisé et d'une analyse de workflow pilotée par IA pour la longue traîne par application.
Le test manuel de logique métier suit un workflow méthodique. L'ordre des opérations compte plus que l'outillage.
Étape 1 — Cartographier le workflow. Parcourez l'application en utilisateur honnête. Utilisez le scanner passif et le sitemap de Burp pour capturer chaque requête qu'un parcours complet effectue — inscription, login, recherche, panier, checkout, post-achat. La sortie est un diagramme de séquence, pas une liste.
Étape 2 — Identifier les endpoints qui changent l'état. Filtrez le sitemap sur les POST, PATCH, PUT et DELETE. Ce sont les endpoints qui valent la peine d'être attaqués. Les GET servent à la découverte et à la vérification.
Étape 3 — Tester les violations de séquence. Rejouez le workflow avec des étapes supprimées (sauter le paiement, aller direct au confirm), répétées (même coupon deux fois d'affilée, deux fois avec un autre entre, trois fois en alterné) et dans le désordre. Un HTTP 200 avec un vrai body de succès est votre signal.
Étape 4 — Tester les bornes arithmétiques. Pour chaque champ numérique — quantity, amount, price, count, limit — rejouez avec -1, 0, 2147483648 (INT32_MAX+1), 9223372036854775808 (INT64_MAX+1), NaN, Infinity, 0.000001. Surveillez les 200 qui auraient dû être des 400.
Étape 5 — Tester la concurrence. Choisissez les endpoints qui modifient des ressources à usage unique (redemption de coupon, application de carte cadeau, soumission d'OTP, transition de rôle, retrait). Envoyez 15 à 30 requêtes identiques dans une seule rafale multiplexée HTTP/2 en utilisant le mode engine=HTTP2 de Burp Turbo Intruder ou h2spacex pour la single-packet attack. Cherchez success_count > 1 avec des codes de statut incohérents — l'empreinte d'une race TOCTOU.
La single-packet attack est la technique la plus sous-estimée du pentest web moderne. Le papier de James Kettle en 2023 a démontré que le multiplexage HTTP/2 réduit le jitter des requêtes concurrentes de millisecondes à microsecondes, transformant des race conditions auparavant théoriques en findings fiables et détectables programmatiquement. Chaque test de race condition en 2026 devrait l'utiliser par défaut.
La défense est architecturale et tient en quatre principes. Chacun mérite son propre deep dive (voir la page pilier pour la section Prevention complète), mais les règles principales sont :
Autorité côté serveur. Ne faites jamais confiance à un price, total, discount_amount, is_admin, role, tenant_id fourni par le client, ni à aucune valeur qui affecte l'autorisation ou l'argent. Recalculez chaque total financier depuis un catalogue côté serveur. Filtrez tout champ supplémentaire du JSON entrant avant de le mapper à votre modèle.
Transitions d'état atomiques. Quand une requête modifie un état partagé (redemption de coupon, retrait de solde, attribution de rôle), enveloppez la séquence read-check-write dans une transaction de base de données avec SELECT ... FOR UPDATE ou un verrou consultatif équivalent. La transaction doit être de la plus petite portée possible autour de la mutation réelle.
Clés d'idempotence. Exigez un en-tête Idempotency-Key sur chaque requête qui change l'état. Stockez la clé + la réponse dans un cache avec TTL ; sur les clés dupliquées dans la fenêtre, rejouez la réponse originale au lieu de réexécuter. Ceci neutralise toute la classe race-condition comme effet de bord.
Imposition par machine à états. Modélisez les workflows multi-étapes comme une machine à états explicite côté serveur. Chaque transition est une méthode qui asserte l'état courant. Sauter une étape devient un 403 Forbidden au lieu d'une acceptation silencieuse.
Voici le principe 4 rendu concret en Python :
class CheckoutState(str, Enum):
CART = "cart"
ADDRESS_PROVIDED = "address_provided"
PAYMENT_AUTHORIZED = "payment_authorized"
CONFIRMED = "confirmed"
ALLOWED_TRANSITIONS = {
CheckoutState.CART: {CheckoutState.ADDRESS_PROVIDED},
CheckoutState.ADDRESS_PROVIDED: {CheckoutState.PAYMENT_AUTHORIZED},
CheckoutState.PAYMENT_AUTHORIZED: {CheckoutState.CONFIRMED},
CheckoutState.CONFIRMED: set(),
}
def transition(order_id: int, target: CheckoutState) -> None:
with db.transaction():
order = db.orders.select_for_update(id=order_id) # row lock
if target not in ALLOWED_TRANSITIONS[order.state]:
raise Forbidden(f"Cannot go from {order.state} to {target}")
order.state = target
order.save()Le select_for_update couple les principes 2 et 4 : même si deux requêtes concurrentes essaient toutes deux de faire avancer la même commande de PAYMENT_AUTHORIZED à CONFIRMED, une seule détiendra le verrou, et la seconde verra l'état mis à jour et échouera correctement. C'est exactement le pattern que PostgreSQL livre dans sa documentation ; le bug, c'est presque toujours oublier de l'utiliser, pas l'absence de la primitive.
Choisissez vos deep dives selon l'application que vous allez tester :
Pour la référence complète cross-classes avec les principes de prévention détaillés, voir le pilier Vulnérabilités de logique métier. Pour opérationnaliser tout cela contre vos propres cibles, le scanner BreachVex apporte une détection de logique métier dédiée couvrant les six classes de variantes, un moteur de règles YAML personnalisé et une analyse de workflow OpenAPI pilotée par IA — exactement la longue traîne que le DAST commodity ne peut pas atteindre.
Les vulnérabilités techniques comme l'injection SQL ou XSS exploitent des entrées malformées que l'application ne sanitise pas — un seul payload déclenche le bug. Les failles de logique métier utilisent des requêtes parfaitement bien formées dans des séquences ou combinaisons non prévues : appliquer le même coupon deux fois, envoyer une quantité négative ou sauter l'étape de paiement. La requête paraît légitime à n'importe quel scanner, c'est pourquoi six variantes dédiées existent (manipulation de prix, quantité négative, stacking de coupons, contournement de workflow, dépassement de limite, arrondi monétaire) et pourquoi elles exigent une compréhension du workflow plutôt que du fuzzing de payload.
Les outils DAST traditionnels (ZAP, Burp Scanner, Nuclei, Acunetix) fonctionnent en rejouant des endpoints avec des payloads de fuzzing et en surveillant des signatures connues — erreurs SQL, canaris XSS, hits DNS OOB. Les exploits de logique métier ne sont pas des entrées malformées ; ce sont des requêtes valides dans des séquences invalides. La détection exige de modéliser l'état applicatif à travers plusieurs requêtes coordonnées, de reconnaître que 30 utilisations réussies sur un coupon à usage unique est un bug, et de comprendre à quoi ressemble un checkout honnête. De nouveaux outils comme Pynt, Escape BLST et StackHawk BLT progressent, mais nécessitent toujours une configuration humaine importante.
Commencez par parcourir l'application cible en tant qu'utilisateur honnête — inscription, login, recherche, ajout au panier, checkout — et capturez chaque requête avec Burp Suite. Lisez ensuite les six deep dives par variante de cette bibliothèque : manipulation de prix, quantité négative, stacking de coupons, contournement de workflow, dépassement de limite et arrondi monétaire. Entraînez-vous sur les labs de la PortSwigger Web Security Academy, qui incluent des exercices gratuits de logique métier mappés à chaque classe. Le changement de mentalité est plus difficile que l'outillage : vous devez comprendre ce que l'application est censée faire avant de pouvoir la casser.
La manipulation de prix et le contournement d'étape de workflow dominent les rapports de bounty réels en e-commerce, tandis que le stacking de coupons via race conditions arrive en tête des rapports fintech. Le cas Stripe HackerOne #1849626 (30 utilisations sur un coupon max_redemptions=1 via single-packet attack HTTP/2) montre comment les race conditions amplifient les failles de dépassement de limite en bounties à six chiffres. Pour les plateformes SaaS, le contournement d'étape de workflow et l'évasion de quotas par tier sont les plus rapportés. La bibliothèque /learn propose des deep dives dédiés pour les six classes dominantes.
Le test manuel de logique métier prend 4 à 40 heures par cible selon la complexité — bien plus long que le scan automatisé. La cartographie du workflow seule (Étape 1 de la méthodologie) prend 1 à 3 heures sur une application non triviale. Le test de race condition exige le setup de Burp Turbo Intruder et la vérification par single-packet attack HTTP/2. La récompense, c'est que ces failles paient des bounties de 25 000 $ à 500 000 $ parce que la profondeur manuelle est la seule manière de les trouver, et c'est précisément pourquoi les pentesters d'élite se spécialisent dans cette classe pendant que les scanners DAST restent aveugles.
La boîte à outils de base est Burp Suite Professional (Repeater, Turbo Intruder pour les single-packet attacks HTTP/2, Logger++) plus Postman ou HTTPie pour le replay d'API. Les outils spécialisés incluent h2spacex pour les race conditions, Pynt et Escape BLST pour les tests de workflow automatisés, et StackHawk BLT (2025) pour l'intégration CI. BreachVex couvre les six classes de variantes grâce à une capacité de détection de logique métier dédiée, plus un moteur de règles YAML personnalisé et une analyse de workflow OpenAPI pilotée par IA pour la longue traîne que le DAST commodity ne peut pas atteindre.
Oui — les vulnérabilités de logique métier sont mappées à OWASP A04:2021 (Insecure Design, renommée A06:2025 — Insecure Design dans le Top 10:2025) et au catalogue OWASP Top 10 BLA 2025, avec des scores CVSS allant de 6,5 (medium) à 9,8 (critical) selon l'impact. Les exemples réels incluent CVE-2023-45854 (Shopkit, CVSS 7.5, integer overflow sur quantité) et CVE-2025-31161 (abus d'arrondi fintech). La fourchette de bounty HackerOne (25 000 $ à 500 000 $) reflète la sévérité : ces bugs entraînent typiquement une perte financière directe, une compromission d'intégrité des données ou un contournement complet d'autorisation, sans payload détectable dans les logs WAF.