TL;DR: Auf der Startseite sah das Consent-Setup vorbildlich aus — Tracking-Tags wurden in
text/plain-Templates umgeschrieben und warteten auf die Einwilligung. Auf/impressum,/datenschutz,/user/loginund einer AJAX-Newsletter-Route derselben Plattform wurden dieselben Tags als ausführbare Skripte gerendert: Analytics und ein Meta-Pixel feuerten ohne Einwilligung, ein Endgeräte-Cookie wurde ohneSecuregesetzt, und es erschien kein Banner. Vier Domains, derselbe Defekt. Die Lehre: Consent-Software ist ein Attachment-Problem — und man testet jede Routenklasse, nicht das Banner.
Die Ausgangslage
Eine kommunale Marketing-Organisation betreibt ihre Stadtmarke auf einer Drupal-Multisite mit vier Domains. Eine Plattform, ein Consent-Manager, ein Analytics-Stack. Ich sollte den Webauftritt von Ende zu Ende prüfen — und begann dort, wo jeder Besucher beginnt: Startseite, Rechtsseiten, Login, Formulare.
Die Startseite war beruhigend. Der Consent-Manager schrieb jedes Tracking-Tag in einen inerten Template-Typ um, Analytics- und Pixel-Bibliotheken luden erst nach der Einwilligung, und ein frisches Browserprofil zeigte null Third-Party-Requests. So soll das aussehen.
Dann richtete ich denselben Test mit frischem Profil auf die Rechtsseiten — auf die Seiten, die ein Besucher genau deshalb öffnet, um zu verstehen, was mit seinen Daten passiert. Dort feuerte das Tracking sofort: kein Banner, keine Einwilligung, trotzdem Speicherzugriff.
Ich habe alle identifizierenden Informationen entfernt. Das Ziel ist nur nach Branche und Technologieklasse beschrieben, damit das Muster wiederverwendbar bleibt.
Das Muster
Ein Consent-Setup ist nur so gut wie seine Routen-Abdeckung
Der Defekt war kein kaputtes Banner und kein falsch konfigurierter Dienst. Die Consent-Bibliothek, die Tracking-Tags in Opt-in-Templates umschreibt, war auf Inhaltsseiten angehängt — und auf den System- und Rechtsrouten nicht. Dort renderten dieselben Tracking-Module als normale, ausführbare Skripte. Der Besucher wird ausgerechnet auf den Seiten getrackt, auf denen die Website erklärt, dass ohne Einwilligung niemals getrackt würde.
Der Beweis ist eine Routen-Matrix, keine Einzelprüfung
Eine einzelne Prüfung auf der Startseite beweist nichts. Entscheidend war derselbe Probe-Lauf über jede Routenklasse: Inhalte, Rechtsseiten, Login, AJAX-Endpunkte und die Fehlerseite. Das Ergebnis war eine Matrix mit einer grünen Zeile (Inhalte) und vier roten (System und Recht). Ein frisches Browserprofil, Cache-Busting und keine Interaktion sind zwingend — ein warmer Cache oder eine frühere Consent-Entscheidung verdeckt den Defekt.
Die Ursache war im HTML sichtbar
Auf gated Seiten tragen die Tags type="text/plain" und ein data-cookieconsent-Attribut; Konfiguration und Preloader der Consent-Bibliothek stehen im Quelltext. Auf den betroffenen Routen fehlten diese Referenzen vollständig — null Verweise auf die Consent-Bibliothek im HTML, während die Tracking-Skripte als ausführbare <script>-Elemente ausgegeben wurden. Die 404-Seite band die Bibliothek dagegen wieder ein. Damit ist es ein routenabhängiger Attachment-Bug, keine globale Fehlkonfiguration: Das Modulverhalten ist korrekt, der Attachment-Scope ist falsch.
Befunde
| Schwere | Befund | Beleg |
|---|---|---|
| HOCH | Consent-Gate fehlt auf System- und Rechtsrouten aller vier Domains | Frisches Headless-Profil: Analytics + Meta-Pixel laden, _fbp ohne Secure gesetzt, kein Banner; Inhaltsseiten korrekt gated |
| MITTEL | Zwei Domains der Familie ganz ohne SPF, eine ohne DMARC/DKIM | DNS-TXT-Records; gefälschte Mails im Markennamen sind zustellbar |
| MITTEL | Öffentlicher Modul-Bauplan (README, 11 KB) auf allen vier Domains | Importer, externer API-Endpunkt, Klartext-Key-Hinweis, nächtliche Cron-Zeiten |
| MITTEL | Modul-Test-Skript auf allen vier Domains anonym ausführbar | HTTP-200-JSON-Endpunkt in Produktion erreichbar |
| MITTEL | Analytics-Server drei Security-Releases hinterher | Version durch öffentliche Changelog-Datei offengelegt; XSS-Escaping-Fixes fehlen |
| NIEDRIG | Versions-Offenlegung, keine security.txt, kein CAA, Installer-Redirect über Klartext-HTTP | Header und DNS |
Der Angriffspfad
Reproduktion im Labor
Jede Probe unten richtet sich gegen eine selbst kontrollierte Lab-Multisite. Nichts davon zielt auf ein Live-System.
# 1. Kontrolle: Gated die Inhaltsseite ihre Tags und hängt sie die Bibliothek an?
curl -s http://lab.local/ | grep -o 'type="text/plain"[^>]*' | head -3
curl -s http://lab.local/ | grep -c 'consent-preloader'
# <- inerte Template-Tags, Preloader vorhanden
# 2. Dieselbe Prüfung auf einer Systemroute
curl -s http://lab.local/user/login | grep -c 'consent-preloader'
curl -s http://lab.local/user/login | grep -c 'var _paq'
# <- 0 Bibliotheks-Referenzen, ausführbarer Analytics-Schnipsel
# 3. Der eigentliche Test: frisches Profil, keine Interaktion, pro Routenklasse
for u in / /impressum /datenschutz /user/login /ajax/newsletter; do
TARGET="http://lab.local$u" node consent-audit.js
done
# <- frisches Profil auf den Rechtsrouten: Third-Party-Requests + Cookie, kein Banner
# consent-audit.js prüft, pro Route:
# Third-Party-Requests vor Consent == 0
# Cookies vor Consent == 0
# Banner sichtbar, sobald Tracking existiert == true
# jede Route, die die ersten beiden Zusicherungen verletzt, ist ein Befund.
Erkennung im eigenen Bestand
- Teste Routenklassen, nicht Seiten: Inhalte, Rechtsseiten, Login, AJAX-Endpunkte, Suche, Fehlerseite, Druckansichten. Consent-Bibliotheken hängen pro Route an; ein ausgenommenes Template reicht.
- Nutze für jede Probe ein frisches Browserprofil mit deaktiviertem Cache. Eine frühere Consent-Entscheidung oder ein warmer Seiten-Cache zeigt grün, wo der Besucher rot sieht.
- Prüfe das HTML-Differential: Gated Tags tragen
type="text/plain"plus Consent-Attribut, und die Bibliotheks-Konfiguration steht im Quelltext. Stehen Tracking-Tags auf einer Route in ausführbaren<script>-Elementen, fehlt dort das Gate — unabhängig davon, was das Banner behauptet. - Prüfe das Ergebnis, nicht das Tooling: null Third-Party-Requests und null Cookies vor Opt-in. Mach daraus einen CI-Check über eine Routenliste und alarmiere bei Regressionen.
- Halte die Datenschutzerklärung konsistent mit der Realität. Ein Pixel, der als „berechtigtes Interesse" beschrieben ist, während die Consent-Konfiguration ihn mit
needConsentführt, ist ein Widerspruch, den ein Prüfer findet.
Behebung
# sofort
1. Consent-Bibliothek global anhängen (Drupal: hook_page_attachments),
nicht über Blöcke pro Route; die Block-Sichtbarkeit korrigieren, die
System- und Rechtsrouten ausschließt
2. AJAX-Newsletter-Route entfernen oder gaten; alle Caches leeren
3. Headless gegenprüfen, pro Routenklasse: 0 Third-Party-Requests vor Consent
4. tests/, docs/ und README* unter /modules/ blocken; Klartext-Key rotieren
# innerhalb einer Woche
5. Analytics-Server über die fehlenden Security-Releases aktualisieren
6. E-Mail-Policy vereinheitlichen: SPF -all, DKIM und DMARC auf jeder Domain
7. Header-Baseline auf jedem Vhost: HSTS, CSP, X-Frame-Options,
Referrer-Policy, Permissions-Policy
# innerhalb eines Monats
8. Regressionstest in CI und in die Rollout-Checkliste jeder
Consent-Tool- oder Template-Änderung aufnehmen
Sobald ein Angreifer Zugriff hat, kann er folgende Aktionen durchführen:
Fazit
- Ein Consent-Banner ist kein Consent-Gate. Entscheidend ist, ob die Tracking-Tags auf jeder Route inert sind — und das ist eine Attachment-Frage, keine UI-Frage.
- Die Seiten, die Nutzer zum Thema Tracking aufsuchen, sind der schlechteste Ort für einen Bypass. Teste Rechtsseiten zuerst, nicht zuletzt.
- Eine grüne Startseiten-Zeile bedeutet nichts. Nur eine Routen-Matrix mit frischen Profilen ist ein ehrlicher Test.
- Derselbe Bestand hat selten genau einen Rest. Ein Routen-Scope-Bug sitzt neben öffentlicher Modul-Dokumentation, einem offenen Test-Endpunkt und einer gespaltenen E-Mail-Policy.
- Fix das Attachment einmal und verifiziere das Ergebnis pro Route in CI — sonst öffnet die nächste Template-Änderung das Gate still wieder.