Une Content-Security-Policy bien construite répond à une question : d’où cette page a-t-elle le droit de charger des scripts ?
Le DOM XSS ne charge aucun script. Il prend une chaîne de caractères à laquelle l’application fait déjà confiance et la passe à une API du navigateur qui transforme les chaînes en code. innerHTML. document.write. eval. Le script ne traverse jamais le réseau, il n’y a donc aucune origine que la CSP puisse autoriser ou refuser.
C’est pourquoi des équipes disposant d’une CSP à nonce et d’un rapport d’en-têtes de sécurité impeccable livrent encore du DOM XSS.
Ce que change Trusted Types
Trusted Types inverse le problème. Au lieu de chercher à identifier les chaînes dangereuses, il empêche les API dangereuses d’accepter la moindre chaîne.
Avec Trusted Types appliqué, element.innerHTML = saisieUtilisateur lève une exception. Le seul moyen d’écrire dans ce point d’injection est de passer un objet TrustedHTML, et le seul moyen d’en obtenir un est de passer par une politique que vous avez déclarée explicitement :
const policy = trustedTypes.createPolicy('sanitizer', {
createHTML: (input) => DOMPurify.sanitize(input),
});
element.innerHTML = policy.createHTML(saisieUtilisateur);
La propriété de sécurité est structurelle et non comportementale. Tout chemin vers un point d’injection DOM passe désormais par du code que vous avez nommé, ce qui fait passer la question d’audit de « nos quatre cents affectations sont-elles toutes sûres ? » à « ces trois politiques sont-elles correctes ? ».
C’est une question à laquelle un humain peut réellement répondre.
Les deux directives
Content-Security-Policy:
require-trusted-types-for 'script';
trusted-types sanitizer default;
require-trusted-types-for 'script' active l’application aux points d’injection.
trusted-types déclare la liste blanche des noms de politiques. Celle-ci s’oublie facilement et mérite d’être conservée. Sans elle, n’importe quel code de la page, y compris un script tiers compromis, peut appeler createPolicy() avec n’importe quel nom et fabriquer des valeurs de confiance. Avec elle, createPolicy() lève une exception sur un nom non listé, donc l’ensemble des chemins de code capables de produire des valeurs de confiance est fixé et relisible.
Une CSP portant require-trusted-types-for sans trusted-types a l’application et perd la traçabilité. C’est un déploiement réel mais partiel.
Support navigateur
Trusted Types fonctionne sur les versions courantes des navigateurs depuis février 2026. Les versions plus anciennes ignorent purement les directives, ce qui rend le déploiement sans risque : les navigateurs non compatibles se comportent exactement comme aujourd’hui, et les compatibles obtiennent la protection.
Il n’existe aucun argument de compatibilité pour attendre.
Déployer sans casser l’application
L’application est stricte, et une base de code existante comportera des violations. Commencez en report-only.
- Livrez
Content-Security-Policy-Report-Onlyavec les deux directives et un point de collectereport-to. - Collectez les violations. Chacune est une véritable affectation vers un point d’injection DOM, et le rapport vous donne le fichier et la ligne.
- Faites passer chacune par une politique, ou supprimez l’affectation.
- Ajoutez une politique
defaultcomme sas temporaire si le volume est important. Elle rattrape tout ce qui n’est pas encore migré, ce qui permet d’appliquer plus tôt et de réduire le sas dans le temps. - Basculez l’en-tête en mode application.
L’étape de remontée apporte de la valeur avant même l’application, car la liste des violations est un inventaire des points d’injection DOM qu’aucune analyse statique ne produit avec autant de justesse.
L’associer au reste de la politique
Trusted Types est une couche. Les autres pièces d’une CSP moderne :
| Directive | Arrête |
|---|---|
script-src avec nonce et strict-dynamic | Les scripts externes injectés |
object-src 'none' | L’exécution via plugins |
base-uri 'self' | L’injection de <base> détournant les URL relatives |
frame-ancestors 'none' | Le clickjacking, plus finement que X-Frame-Options |
require-trusted-types-for 'script' | Le DOM XSS au point d’injection |
Les politiques script-src à liste blanche sont aujourd’hui déconseillées : elles deviennent ingérables et sont régulièrement contournables via les origines autorisées elles-mêmes. Nonce plus strict-dynamic est la recommandation actuelle.
Il faut savoir ce que la CSP ne couvre pas du tout : les vulnérabilités côté serveur, et la compromission de la chaîne d’approvisionnement d’une source de scripts à laquelle vous faites déjà confiance. Pour ce second point, il vous faut Subresource Integrity et son en-tête d’application.
Où cela se mappe en conformité
- NIS2 article 21(2)(g), hygiène informatique de base, et 21(2)(e), sécurité des réseaux et des systèmes.
- ISO/IEC 27001:2022 A.8.28 (développement sécurisé) et A.8.26 (exigences de sécurité applicative).
- OWASP Top 10 A03:2021, injection.
Comment le vérifier
curl -sI https://votredomaine.fr | grep -i content-security-policy
Cherchez les deux directives. Un scan SaaSFort rapporte trois états distincts, car ce sont réellement des postures différentes : les deux directives présentes, l’application sans liste blanche, et aucune des deux.
En résumé
La CSP contrôle les sources de scripts. Trusted Types contrôle les points d’injection. Les deux traitent des moitiés différentes de la même classe d’attaque, et la plupart des applications SaaS en 2026 n’ont déployé que la première moitié.
Le mode report-only ne coûte rien et produit un inventaire de tous les points d’injection DOM de votre application. Commencez par là.
Passez de la lecture à l'action
Scannez votre domaine gratuitement. Premiers résultats en moins de 10 secondes — sans inscription.