Un audit de sécurité d''appli web en 2026, ce n''est pas pointer un scanner sur l''URL de prod et lire le rapport, parce que ça couvre peut-être un quart de ce qui peut réellement vous faire mal. La surface a grossi pendant que personne ne regardait. Les API REST et GraphQL font passer plus de trafic que les pages HTML sur la plupart des stacks que je touche. Les pipelines CI/CD sont bourrés de tokens à longue durée de vie qui déploient direct en prod. Et l''arbre de dépendances d''une appli même moyenne traîne des centaines de paquets transitifs. Du coup je travaille en quatre couches : transport, code applicatif, supply chain, secrets. Voici la méthodologie que j''applique vraiment, les outils et la config exacts, plus une checklist en 25 points à coller dans votre wiki.
The short answer
Menez un audit de sécurité d'appli web moderne en quatre couches travaillées dans l'ordre : transport (TLS, HSTS, six en-têtes, CORS), code applicatif (auth, IDOR, limites GraphQL, uploads, SSRF), supply chain (dépendances, lockfiles, images de conteneurs, workflows CI) et secrets (stockage en vault, scope, rotation). L'ordre compte, chaque couche rend la suivante plus facile, et une checklist en 25 points vient tout clôturer.
Vous pensez encore qu'un audit de sécurité, ça revient à « pointer un scanner sur l'URL de prod et lire le rapport » ? Alors vous auditez peut-être un quart de ce qui peut réellement vous faire mal. La surface a grossi pendant que personne ne regardait. Sur la plupart des stacks que je touche, les API REST et GraphQL font passer plus de trafic que les pages HTML. Les pipelines CI/CD sont bourrés de tokens à longue durée de vie qui déploient direct en prod. Et l'arbre de dépendances d'une appli même de taille moyenne traîne derrière lui des centaines de paquets transitifs, dont n'importe lequel peut être empoisonné par un seul mainteneur fatigué. Du coup je travaille en quatre couches : transport, code applicatif, supply chain, secrets. Ce qui suit, c'est la méthodologie que j'applique vraiment. Avec des partis pris. Les outils et la config exacts que j'utilise, plus une checklist en 25 points à la fin que vous pouvez coller telle quelle dans le wiki de votre équipe.
Pourquoi un audit 2026 n'a rien à voir avec un audit 2022
Trois choses ont bougé sous nos pieds en trois ans. D'abord, les API ont avalé le trafic. Une appli moderne expose une surface REST ou GraphQL qu'une SPA, un client mobile et deux ou trois intégrations greffées tapent toutes en parallèle, et un scanner en boîte noire qui suit les parcours humains l'effleure à peine. J'ai déjà vu un scan ressortir tout vert sur les pages marketing pendant qu'un endpoint d'introspection GraphQL non authentifié distribuait tranquillement tout le schéma, chaque mutation comprise. Rapport nickel. Porte grande ouverte.
Ensuite, le pipeline est devenu une surface d'attaque. Toute appli un tant soit peu sérieuse passe par GitHub Actions, GitLab CI, CircleCI, ou par le Jenkins de quelqu'un, tendrement laissé à l'abandon dans un placard. Ces pipelines détiennent les tokens de déploiement, les creds cloud, les mots de passe de registry, tout le trousseau. Du coup je lis la config du pipeline aussi attentivement que je lis le code applicatif. Soyons clairs : un fichier de workflow qu'un attaquant peut éditer, c'est une clé de prod qu'un attaquant peut utiliser. Même chose, autre extension de fichier.
Enfin, presque tout appelle un LLM maintenant. La plupart des applis non triviales que je vois tapent au moins une API de modèle, et beaucoup branchent du RAG sur un vector store rempli de données clients. Prompt injection, y compris la variante indirecte qui arrive en stop sur du contenu scrapé. Données qui filent dehors via une réponse du modèle. Honnêtement je pense qu'on a sous-estimé la vitesse à laquelle ça a bougé, parce que ce ne sont plus des curiosités de conférence : ce sont devenus de vraies findings sur de vrais audits. Elles vivent pile à l'endroit où la logique applicative rencontre le risque supply chain, alors oui, elles vont sur la liste.
Les quatre couches et leur correspondance avec l'OWASP 2025
Quand l'OWASP a rebattu les cartes de son Top 10 fin 2025, c'était au fond pour rattraper cette surface élargie. Mon modèle en quatre couches colle à cette mise à jour. Et plus utile encore, il vous donne un ordre dans lequel travailler au lieu d'un tas de findings que vous fixez du regard avec une appréhension sourde.
- Transport et réseau. Config TLS, HSTS, votre posture CORS, les origines autorisées, les rate limits posés à la périphérie. Correspond à A05 (Security Misconfiguration) et A07 (Identification and Authentication Failures).
- Code applicatif. Authentification, autorisation, validation des entrées, encodage des sorties, SSRF, failles de logique métier, introspection GraphQL, la façon dont vous gérez les uploads de fichiers. Correspond à A01 (Broken Access Control), A03 (Injection), A04 (Insecure Design), A10 (SSRF).
- Supply chain. Dépendances directes et transitives, registries de paquets, images de base de conteneurs, modules IaC, références GitHub Actions ou GitLab CI. Correspond à A06 (Vulnerable and Outdated Components) et A08 (Software and Data Integrity Failures).
- Gestion des secrets. Tokens, clés d'API, URLs de base de données, clés de signature JWT, clés de chiffrement au repos. Correspond à A02 (Cryptographic Failures) et à la toute nouvelle entrée 2025 sur l'exposition des secrets dans les pipelines.
L'ordre n'est pas arbitraire. Chaque couche rend la suivante plus facile. Verrouillez le transport et un paquet de findings de la couche deux cessent tout simplement d'être exploitables. Nettoyez l'arbre de dépendances et le scoping des secrets devient un boulot fini au lieu d'un boulot infini. Une base de secrets bien serrée vient ensuite éponger ce qui aurait filé entre les mailles des trois premières. Sautez des étapes et vous referez du travail. Je l'ai appris à la dure, lentement.
Couche 1 : transport et réseau
La couche la moins chère à auditer. Et aussi celle que je vois le plus souvent partir en vrille en prod, ce qui ne cesse jamais d'être drôle, d'une drôlerie un peu triste. Quatre choses à regarder : le certif TLS, la mise en place HSTS, la base d'en-têtes de sécurité, la politique CORS. Rien de compliqué. Les équipes zappent quand même.
Configuration TLS
Ce que je cherche : TLS 1.3 activé, TLS 1.0 et 1.1 explicitement coupés, un certificat ECDSA ou RSA-2048+, OCSP stapling activé, une chaîne valide avec au moins 30 jours avant expiration. Mettez en place un monitor qui vous bipe à 14 jours. C'est assez de marge pour renouveler sans la panique de 2 h du mat. Et ne validez pas la couche tant que SSL Labs ne vous donne pas un A ou un A+. Quand je récolte un A-, neuf fois sur dix c'est du TLS 1.0 qui répond encore sur un vieux serveur d'origine legacy que tout le monde avait oublié.
HSTS et en-têtes de sécurité
Ma base pour toute appli publique, c'est six en-têtes : Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, Permissions-Policy et X-Frame-Options (ou, à la mode moderne, frame-ancestors dans le CSP). Pour HSTS, ne descendez pas sous un an, sous-domaines couverts :
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Si vous ne corrigez qu'un seul en-tête, corrigez le CSP. Il vous rapporte plus que les cinq autres réunis. Voici un point de départ strict qui tient la route pour la plupart des applis React, Vue ou Next.js :
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-...';
style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;
connect-src 'self' https://api.your-domain.com;
frame-ancestors 'self'; base-uri 'self'; form-action 'self';
report-uri /csp-report;
Lancez-le d'abord en mode report-only pendant deux semaines. Collectez les violations, voyez ce qui casse légitimement, puis basculez en enforce. Chaque fois, absolument chaque fois que j'ai vu quelqu'un sauter la phase report-only, le CSP a mis hors service une partie du site le jour du déploiement. En général un vendredi. En général le vendredi avant un lancement.
CORS
CORS, c'est là que les fuites continuent d'arriver. Mon pattern : lister chaque endpoint cross-origin, puis vérifier qu'Access-Control-Allow-Origin est une origine précise ou une vraie allow-list. Jamais un wildcard assis à côté d'Access-Control-Allow-Credentials: true. Cette combinaison-là est un chemin d'exfiltration de credentials pur et simple. C'est sur la cheat sheet de l'OWASP depuis dix ans et je tombe encore dessus en prod à peu près une fois par trimestre, ce qui honnêtement me déprime un peu.
Si votre API lit des tokens depuis l'en-tête Authorization, confirmez que le preflight est géré exprès, pas juste laissé au défaut du framework. Express, Fastify, FastAPI et Django livrent tous des défauts sains aujourd'hui. Mais le défaut sain perd presque toujours face à un middleware « allow all » copié-collé pendant le prototype et que personne n'a jamais resserré. C'est la ligne que je grep en premier, à chaque fois.
Couche 2 : code applicatif
C'est la grosse. Et c'est aussi là qu'un scanner seul ne vous achètera jamais la tranquillité. Je découpe en trois paniers que je traite un par un : la surface HTML/SPA, la surface API, les uploads de fichiers. Essayer de tenir les trois en tête en même temps, c'est exactement comme ça que des trucs passent au travers.
La surface HTML et SPA
Sur les pages rendues côté serveur, je chasse la famille d'injection classique. Stored XSS dans tout ce qui est généré par l'utilisateur, reflected XSS dans les pages de recherche et d'erreur. Puis server-side template injection partout où une entrée utilisateur atterrit dans un moteur de templates. Les SPA ont le même problème déguisé autrement : tout HTML qui sort via innerHTML ou via le dangerouslySetInnerHTML de React vient soit d'une source de confiance, soit passe par DOMPurify. Pas d'exception. Une passe avec Semgrep ou les règles de sécurité d'ESLint attrape les évidences et vous libère l'esprit pour réfléchir aux cas qui demandent vraiment un cerveau humain.
La surface API
Avec REST, c'est surtout un exercice de contrôle d'accès. Chaque endpoint a besoin d'auth sauf s'il est public exprès. Chaque endpoint authentifié doit imposer des contrôles au niveau objet, le classique « l'utilisateur 42 ne peut pas lire la facture de l'utilisateur 43 », parce que ce bug IDOR-là revient plus souvent que n'importe quel autre sur de vrais audits. Et chaque mutation valide le corps de requête contre un schéma au lieu de faire confiance à ce que le désérialiseur a recraché. GraphQL en rajoute une couche. Coupez l'introspection en prod, et plafonnez la profondeur et la complexité des requêtes au niveau du resolver pour que personne ne vous DoS avec une requête profondément imbriquée. Imposez aussi l'autorisation champ par champ. Un accès en lecture à Order ne doit pas accorder en douce un accès en lecture à Order.customer.creditCardLast4, et par défaut c'est exactement ce qui arrive.
La plupart des équipes avec qui je bosse partent contract-first : un doc OpenAPI ou GraphQL SDL est la source de vérité et l'implémentation est vérifiée contre lui. Bien. Mais n'oubliez pas d'auditer le contrat lui-même. J'ai vu la spec laisser fuiter des champs sensibles, ou confier une opération réservée aux admins au rôle public, et personne ne l'a remis en question parce que, eh bien, c'était « le contrat ».
La surface d'upload de fichiers
Les uploads de fichiers ne reviennent pas souvent. Mais quand ça dérape, ça dérape salement. Donc : validez le MIME et les magic bytes côté serveur, et ne faites jamais, au grand jamais, confiance à l'en-tête Content-Type du client. Ce champ est une suggestion, au mieux. Imposez des limites de taille à la fois au serveur web et à l'appli. Écrivez des noms de fichiers randomisés dans un répertoire qui ne peut rien exécuter. Scannez le contenu si vous stockez des documents que les gens téléchargeront ensuite. Et utilisez une allow-list des extensions que vous acceptez au lieu de jouer au chat et à la souris avec une deny-list. Un piège qui mord les gens en silence : le XML. Tout parseur XML sur le chemin a besoin que la résolution des entités externes soit coupée (votre XXE) et que l'expansion des entités soit plafonnée (le billion laughs). Les deux. Pas l'un sans l'autre.
Couche 3 : supply chain
En 2025, la supply chain est passée devant le code applicatif comme cause racine confirmée numéro un des breaches. Posez-vous une seconde là-dessus. Le code que vous n'avez pas écrit a désormais plus de chances de vous couler que celui que vous avez écrit. Quatre familles d'artefacts à vérifier.
Dépendances directes et transitives
Branchez npm audit --omit=dev, pip-audit, bundle audit, cargo audit, ce qui colle à votre stack, dans la CI. La barre que je tiens, c'est zéro critique et zéro high dans l'arbre de prod, avec un SLA écrit pour les medium et les low pour qu'ils ne pourrissent pas là pour l'éternité. Voici l'erreur que je vois en permanence. Les findings dev et prod sont déversés dans un seul flux bruyant, ça devient tellement assourdissant que tout le monde décroche, et au final personne n'en lit aucun. Séparez-les. Un arbre de prod propre que vous regardez vraiment vaut mieux qu'un rapport géant que personne n'ouvre.
Le lockfile est la source de vérité
Auditez le package-lock.json, le yarn.lock ou le Pipfile.lock, pas le manifeste. Le lockfile épingle les versions et les hashes exacts. Un package.json plein de plages avec caret peut se résoudre en douce vers autre chose au prochain run de CI, et voilà que votre build « audité » n'est plus le build qui a été livré. Donc faites en sorte que la CI plante en dur quand le lockfile manque ou est périmé. Sans ça, tout le contrôle supply chain est du théâtre. Vous auditez un instantané qui ne correspondra de toute façon pas à la prod.
Images de base de conteneurs
Si un service est livré sous forme de conteneur, scannez l'image de base avec Trivy, Grype ou Snyk avant que la modif du Dockerfile ne soit mergée. Avant, pas une fois qu'elle est en prod. Épinglez la base à un digest, jamais à un tag, et bumpez le digest selon un planning au lieu de laisser latest dériver sous vos pieds pendant que vous dormez. Les attaques par dependency confusion de 2025 ont rendu le coût bien concret. Un digest pin manquant peut se résoudre vers une image malveillante du jour au lendemain, et vous ne verriez jamais le diff.
Fichiers de workflow CI
Passez en revue chaque .github/workflows/*.yml en cherchant deux choses. Un : des références uses: épinglées à un commit SHA, pas un tag, pas une branche. Deux : des blocs permissions: en moindre privilège posés au niveau du workflow ou du job. Voici pourquoi le SHA compte. actions/checkout@v4 peut devenir malveillant le jour où quelqu'un réécrit le tag v4 en amont, et vous venez de confier tout votre pipeline à cette action. Épinglez-la par SHA et cette attaque ne marche tout simplement pas. Même règle pour l'include: de GitLab CI et les orbs de CircleCI. Épinglez-les aussi.
Couche 4 : gestion des secrets
Envie de rater un audit en un temps record ? Laissez-moi passer gitleaks ou trufflehog sur le dépôt et faire remonter un token vivant. Le dauphin : un secret imprimé dans les logs de GitHub Actions parce que personne n'a ajouté ::add-mask::, posé là en clair pour quiconque a un accès en lecture. Et puis il y a le personal access token à longue durée de vie qui fait le boulot de la CI, parce que mettre en place une vraie deploy key semblait trop pénible cet après-midi-là. J'en trouve au moins un de ces trois-là sur la plupart des premiers audits. La plupart.
Du coup je pose cinq questions. Est-ce que chaque secret est dans un manager, Vault, AWS Secrets Manager, Doppler, GitHub Encrypted Secrets, au lieu du code ou d'un fichier env ? Est-ce qu'il est tourné selon un planning, disons 90 jours pour les puissants et 365 pour le reste ? Est-ce qu'il est scopé au plus petit rayon d'impact que vous pouvez gérer, un projet et un environnement ? Est-ce qu'il y a une alerte quand il est utilisé là où il ne devrait pas l'être, une restriction d'IP, un déclencheur CloudTrail ? Et à la seconde où un nouveau secret est émis, est-ce que l'ancien est vraiment révoqué ? Ou est-ce qu'il reste juste là à respirer, « au cas où » ?
Ce dernier point, c'est là que la plupart des équipes échouent en silence. Les vieux secrets s'accumulent. Et puis le token d'un ex-prestataire se connecte depuis un pays que personne dans l'équipe ne reconnaît, trois ans après que son ticket de départ a été fermé et oublié. Si vous ne faites qu'une seule chose ici, lancez un rapport récurrent « lister chaque secret actif de plus de 365 jours ». Le gain d'hygiène le moins cher que je connaisse. Il fait remonter les tokens fantômes avant que quelqu'un d'autre ne les trouve.
La stack d'outils 2026
Vous pouvez couvrir l'essentiel de cet audit gratuitement. Honnêtement. Voici ce vers quoi je tends vraiment la main : nuclei pour du DAST templaté contre les API, Semgrep pour l'analyse statique (les packs de règles communautaires couvrent déjà les quatre stacks majeures), Trivy pour les conteneurs et l'IaC, gitleaks ou trufflehog pour les secrets, OWASP ZAP quand j'ai besoin de piloter un vrai navigateur à travers des parcours authentifiés, et SSLLabs, le service public gratuit, pour noter le TLS. C'est un kit vraiment capable. Et ça ne coûte rien.
Le niveau payant achète de la profondeur, pas de la magie. Snyk ou GitHub Advanced Security surveilleront l'arbre de dépendances en continu et ouvriront des PR de remédiation pour vous. Burp Suite Professional, c'est ce vers quoi je me tourne quand je fais du test d'API sérieux à la main. Et un WAF managé, Cloudflare, AWS WAF, Sucuri, vous donne un filet de sécurité à l'exécution. Ma règle de pouce, et peut-être que je me trompe là-dessus, c'est qu'il se rentabilise vers le troisième cycle d'audit. C'est le moment où les heures que votre équipe brûle en triage commencent à coûter plus cher que la licence.
La checklist d'audit en 25 points
Lancez-la une fois au lancement, encore chaque trimestre, et à chaque fois que l'architecture bouge sous vos pieds. Les sévérités supposent une appli de prod exposée au public. Revoyez-les à la baisse si vous êtes derrière un VPN ou posé sur un réseau interne uniquement.
| # | Vérification | Couche | Sévérité |
|---|---|---|---|
| 1 | TLS 1.3 activé, 1.0 et 1.1 désactivés, certif > 30 jours restants | Transport | Élevée |
| 2 | HSTS avec max-age >= 31536000 + includeSubDomains | Transport | Élevée |
| 3 | CSP au moins à default-src 'self' en mode enforce | Transport | Élevée |
| 4 | Six en-têtes de sécurité présents et corrects | Transport | Moy |
| 5 | Allow-list CORS explicite, pas de combo wildcard + credentials | Transport | Élevée |
| 6 | Rate limits en périphérie configurés par famille de routes | Transport | Moy |
| 7 | Chaque endpoint d'API exige l'auth sauf s'il est public exprès | Application | Élevée |
| 8 | Autorisation au niveau objet imposée (pas d'IDOR) | Application | Élevée |
| 9 | Corps de requête validés contre un schéma | Application | Moy |
| 10 | Introspection GraphQL désactivée en production | Application | Moy |
| 11 | Profondeur et complexité des requêtes GraphQL limitées | Application | Moy |
| 12 | HTML dynamique de la SPA passe par DOMPurify ou équivalent | Application | Élevée |
| 13 | Uploads de fichiers imposent un check MIME et magic-byte côté serveur | Application | Élevée |
| 14 | Parseurs XML avec XXE et expansion d'entités désactivés | Application | Élevée |
| 15 | Mitigations SSRF sur toute fonctionnalité qui fetch une URL | Application | Élevée |
| 16 | Deps directes et transitives scannées, zéro high/critical dans l'arbre de prod | Supply chain | Élevée |
| 17 | Lockfile obligatoire, la CI refuse un lockfile manquant ou périmé | Supply chain | Moy |
| 18 | Images de base de conteneurs épinglées au digest, scannées avec Trivy | Supply chain | Moy |
| 19 | Références uses: de la CI épinglées au commit SHA | Supply chain | Moy |
| 20 | Les workflows CI déclarent des permissions: en moindre privilège | Supply chain | Moy |
| 21 | Tous les secrets dans un vault managé, aucun dans le code ou les fichiers env | Secrets | Élevée |
| 22 | Secrets scopés à un projet et un environnement | Secrets | Élevée |
| 23 | Secrets à haut privilège tournés tous les 90 jours | Secrets | Moy |
| 24 | Vieux secrets révoqués, aucun secret actif de plus de 365 jours | Secrets | Élevée |
| 25 | Dépôt et logs CI scannés avec gitleaks ou trufflehog | Secrets | Élevée |
Sources et lectures complémentaires
Questions fréquentes
Combien de temps prend un audit complet ?
Pour une appli moyenne, un frontend, une API, deux ou trois services, une base de données, comptez environ trois jours d''ingénierie pour la première passe. Ensuite, si l''outillage vit dans la CI, le run trimestriel, c''est une journée. Parfois moins. Le premier traîne toujours en longueur, parce que vous n''êtes pas juste en train d''auditer : vous êtes aussi en train de découvrir où tout se trouve réellement. Cette archéologie-là n''arrive qu''une fois, heureusement.
Quelle est la différence entre un audit de sécurité et un test d'intrusion ?
Un audit est structuré et piloté par checklist. Il vise la complétude sur les quatre couches, l''étendue plutôt que la profondeur. Un pentest, c''est l''inverse : exploratoire, avec un cerveau d''attaquant, à la chasse de cette unique chaîne créative qu''une checklist laisserait filer sans la voir. L''un ne remplace pas l''autre. L''audit vous donne le plancher. Le pentest trouve le chemin tordu auquel personne n''a pensé. Je lance l''audit chaque trimestre et je fais venir un pentest une fois par an.
Faut-il un process SOC2 ou ISO 27001 pour faire ça ?
Non. Rien de tout ça n''a besoin d''un cadre de conformité enroulé autour. Ça tient debout très bien tout seul. Cela dit, si vous êtes déjà sous SOC2, ISO 27001 ou PCI-DSS, cette checklist coche en douce une grosse partie des exigences de contrôle de sécurité de toute façon. Et si la conformité est quelque part à votre horizon, faire le travail maintenant rend cet audit futur bien moins cher et bien moins douloureux.
Comment auditer un SaaS que j'intègre mais que je ne contrôle pas ?
Vous ne pouvez pas pentester le serveur de quelqu''un d''autre. Du coup vous vous appuyez sur des preuves à la place. Demandez leur dernier rapport SOC2, ou remplissez leur questionnaire de sécurité. Vérifiez qu''ils ont une politique de sécurité publique et un moyen de signaler des bugs, parce qu''un fournisseur sans programme de divulgation est un drapeau rouge discret. Confirmez que les données qu''ils touchent sont chiffrées en transit et au repos. Et resserrez le token d''API que votre appli leur confie au scope minimum dont il a réellement besoin. Pour les fournisseurs dont vous ne pouvez pas vous passer, j''intègre une revue annuelle de leur rapport dans la couche trois.
Et la prompt injection et les intégrations d'API d'IA ?
Traitez chaque appel à un LLM comme une frontière d''exécution non fiable, parce que c''est exactement ce que c''est. Tout ce qui vient de l''extérieur (uploads utilisateur, pages scrapées, docs récupérés) est assaini avant même d''atteindre le prompt. Gardez les rôles système et utilisateur séparés. À la seconde où vous les concaténez, vous avez confié vos instructions à l''utilisateur. Validez la sortie aussi : si le modèle a le droit de renvoyer du JSON, vérifiez-le contre un schéma avant que ce résultat ne déclenche quoi que ce soit de sensible. Et logguez les prompts et les réponses pendant au moins 30 jours, parce que quand quelque chose part de travers, ce log est la seule trace forensique que vous aurez.