Comment les attaquants détournent Google Tag Manager, et comment une CSP stricte le contient
CentralCSP Team ·
Dernière mise à jour:
Google Tag Manager (GTM) existe pour injecter des scripts dans vos pages sans déploiement de code. C'est la fonctionnalité, et c'est aussi le risque : celui qui contrôle le conteneur peut livrer du JavaScript arbitraire sur chaque page qui le charge. Un compte compromis, un éditeur malveillant ou un tag tiers détourné peut transformer votre propre outillage d'analytics en canal de livraison pour un skimmer de formjacking. Pour le contenir et le détecter, il faut une politique de sécurité du contenu (CSP) stricte, un header de réponse HTTP qui indique au navigateur quels scripts peuvent s'exécuter, doublée d'un inventaire de scripts et d'alertes de changement.
Ce billet est le pendant sécurité et menaces de CSP pour Google Analytics et Tag Manager, qui couvre la mécanique pour autoriser GTM sous un nonce. Ici la question est différente : qu'est-ce qui peut mal tourner via GTM, et qu'est-ce qui limite les dégâts.
GTM est un canal d'injection de scripts par conception
Quand vous ajoutez le snippet GTM à une page, vous laissez une configuration distante charger et exécuter du code dans votre origine. Quiconque peut publier une version de conteneur, via l'interface GTM ou l'API, décide quel JavaScript s'exécute sur chaque page portant ce conteneur. Les tags tournent avec un accès complet à la page : le DOM, les champs de formulaire, les cookies qui ne sont pas HttpOnly, et tout ce qu'un script côté client peut atteindre.
C'est exactement ce que vous voulez pour des tags légitimes d'analytics et de marketing. C'est aussi exactement ce qu'un attaquant veut. Le mécanisme ne distingue pas un pixel de conversion d'un skimmer de carte.
D'où vient l'abus
Trois scénarios transforment cette possibilité en incident.
- Un compte GTM compromis. Des identifiants hameçonnés ou réutilisés sur un compte avec droits de publication permettent à un attaquant de pousser une version de conteneur malveillante. Aucun changement ne touche votre code ni vos serveurs : votre CI, votre revue de code et vos logs de déploiement n'y voient donc jamais rien.
- Un éditeur aux droits trop larges. Un prestataire ou un utilisateur marketing avec accès en publication, ou un compte obsolète qui aurait dû être supprimé, peut publier un tag qu'aucun ingénieur ne relit, par erreur ou à dessein.
- Un tag tiers détourné. Dès qu'un tag charge le script d'un fournisseur, ce fournisseur (ou quiconque le compromet) peut changer à tout moment ce qui s'exécute sur votre page. Le risque de supply-chain s'étend à chaque host dont vos tags tirent du contenu.
Dans chaque cas, le code malveillant arrive de la même façon que les tags légitimes, c'est pourquoi les défenses côté serveur ne le voient pas. Un pare-feu applicatif inspecte le trafic vers votre origine ; il ne voit pas ce que gtm.js injecte dans le navigateur après le chargement de la page.
Pourquoi allowlister GTM élargit votre périmètre de confiance
La façon courante d'« autoriser » GTM dans une CSP est de lister googletagmanager.com et compagnie dans script-src. Cette allowlist accorde sa confiance à tout script que ces hosts peuvent servir, y compris tout ce que votre conteneur est configuré pour charger aujourd'hui ou demain. Ce n'est pas à un code figé que vous faites confiance, mais à une configuration modifiable, pilotée hors de votre dépôt.
Les allowlists de hosts sont faibles pour une deuxième raison. Toute redirection ouverte, endpoint JSONP ou chemin contrôlé par l'utilisateur sur un host autorisé peut devenir un contournement qui exécute du code choisi par l'attaquant tout en satisfaisant la politique. De larges wildcards Google dans script-src élargissent considérablement cette surface.
Comment une politique stricte à nonce plus strict-dynamic le contient
Une CSP stricte ne fait pas confiance aux hosts. Elle fait confiance à un nonce par requête et utilise 'strict-dynamic' pour étendre cette confiance aux scripts qu'un script porteur de nonce charge. Vous mettez le nonce sur l'amorçage GTM, et le navigateur fait alors confiance à gtm.js et aux tags que GTM injecte parce qu'ils en descendent.
Content-Security-Policy:
script-src 'self' 'nonce-{SERVER-GENERATED-NONCE}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
report-to csp-endpointCela n'empêche pas GTM d'injecter ce que le conteneur est configuré pour injecter ; rien côté client ne le peut, parce que ce code descend de votre amorçage de confiance. En revanche, cela réduit le rayon d'impact autour de GTM. Un attaquant qui trouve une injection ailleurs sur la page (une XSS réfléchie, un fournisseur non-GTM compromis) ne peut pas exécuter de script : il ne peut pas deviner le nonce, et avec 'strict-dynamic', une allowlist de hosts oubliée ne le sauvera pas non plus. La politique garde la confiance étroite : seulement ce que GTM charge, pas tout ce qu'un host autorisé pourrait servir.
Cela rend aussi une classe d'abus de GTM plus bruyante. Les tags qui ont besoin de 'unsafe-eval', comme les variables JavaScript personnalisées, échoueront sous une politique stricte au lieu de tourner en silence, ce qui met ces pratiques au grand jour et vous permet de les relire.
La détection est l'autre moitié : inventaire et alertes
Le confinement limite les dégâts. La détection vous dit quand un conteneur a changé. Comme une compromission de GTM ne touche jamais votre code, le seul endroit où la voir est le navigateur, dans ce qui a réellement tourné sur la page.
Construit à partir du reporting de hash CSP, un inventaire de scripts enregistre chaque script qui s'exécute sur chaque page, avec la technologie, la version et les CVE connues derrière chacun. Quand GTM injecte un nouveau tag, un nouveau script apparaît dans l'inventaire. Les alertes de changement se déclenchent quand l'ensemble des scripts d'une page sensible change : une nouvelle origine, un nouveau bloc inline, un script qui n'était pas là hier. Sur une page de paiement, un nouveau script inattendu est le signal précoce d'un skimmer de type Magecart, le même signal que les exigences côté client de PCI DSS v4 vous demandent de surveiller.
C'est le workflow pour lequel CentralCSP est fait. Il ingère vos reports de violation et de hash CSP, inventorie les scripts que GTM et tout le reste chargent, et alerte sur les changements, pour qu'une version de conteneur malveillante remonte sous forme d'alerte « nouveau script sur la page de paiement » plutôt que dans un rapport de rétrofacturation des semaines plus tard. Commencez par évaluer une politique et ses faiblesses, une large allowlist de hosts Google par exemple, puis démarrez un essai gratuit et pointez-y un header Report-Only pour voir ce que votre conteneur charge vraiment.

Une checklist de confinement pratique
- Faites confiance à GTM via un nonce et
'strict-dynamic', plutôt que par une allowlist de hosts dansscript-src. - Gardez les hosts Google dans
connect-src,img-srcetframe-src, où se produisent les requêtes non-script, pas dansscript-src. - Verrouillez le compte GTM : droits de publication minimaux, MFA, et une revue régulière qui supprime les éditeurs obsolètes.
- Évitez les tags qui forcent
'unsafe-eval'; reconstruisez les variables JavaScript personnalisées en Custom Templates sandboxés. - Inventoriez les scripts sur chaque page sensible et alertez sur le changement, pour voir immédiatement une modification de conteneur que vous n'attendiez pas.
Questions fréquentes
Google Tag Manager peut-il être un risque de sécurité ?
Oui. GTM injecte des scripts dans vos pages depuis une configuration distante, donc un compte compromis, un éditeur aux droits trop larges ou un tag tiers détourné peut exécuter du JavaScript arbitraire sur chaque page qui charge le conteneur. Le risque est inhérent à ce que GTM fait.
GTM contourne-t-il ma CSP ?
Si vous allowlistez des hosts Google dans script-src, GTM et tout ce qu'il charge tournent sous cette allowlist, donc un tag malveillant tourne aussi. Une politique stricte à nonce plus 'strict-dynamic' ne bloque pas GTM (vous lui faites confiance délibérément), mais elle garde la confiance étroite et empêche les injections non liées de s'exécuter.
Comment détecter un tag GTM malveillant ?
Surveillez les scripts qui s'exécutent réellement dans le navigateur. Un inventaire de scripts construit à partir du reporting de hash CSP liste chaque script de chaque page, et les alertes de changement se déclenchent quand un script nouveau ou inattendu apparaît : c'est ainsi qu'une version de conteneur malveillante remonte sans jamais toucher votre code. Les bibliothèques qu'un tag embarque sont détectées de la même façon, avec leur version et leurs CVE connues, donc un widget pas à jour livré par le conteneur est visible lui aussi. Détecter les bibliothèques JavaScript vulnérables sur un site en production couvre cet angle, et un jQuery embarqué en est l'exemple habituel.
GTM est-il un risque Magecart sur les pages de paiement ?
Il peut l'être. Un skimmer livré via un conteneur compromis s'injecte sur la page de paiement comme n'importe quel autre tag. Contenir GTM avec une CSP stricte et surveiller les changements de scripts sur la page de paiement, c'est exactement l'objet des exigences côté client de PCI DSS v4.
À retenir
GTM est un canal d'injection de scripts délibéré, donc sa sécurité se résume à deux choses : limiter ce qu'une injection peut faire, et détecter quand le conteneur change. Une CSP stricte qui fait confiance à un nonce et 'strict-dynamic' plutôt qu'à des allowlists de hosts Google garde le périmètre de confiance serré, et un inventaire de scripts avec alertes de changement vous prévient quand apparaît un tag que personne dans votre équipe n'a livré. Ensemble, ils rendent visible et maîtrisable un changement côté client qui, sinon, passerait inaperçu.
Pour aller plus loin : OWASP sur la sécurité côté client et le Top 10 OWASP et les recommandations de sécurité GTM de Google.
Sources
- Google, utiliser une CSP avec Tag Manager
- OWASP, Top 10 des risques de sécurité des applications web
- W3C, Content Security Policy Level 3