@aegis-scan/skills 0.2.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATTRIBUTION.md +171 -4
- package/CHANGELOG.md +112 -1
- package/README.md +27 -0
- package/dist/skills-loader.d.ts +43 -0
- package/dist/skills-loader.d.ts.map +1 -1
- package/dist/skills-loader.js +102 -0
- package/dist/skills-loader.js.map +1 -1
- package/package.json +1 -1
- package/skills/compliance/_INDEX.md +49 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/CHANGELOG.md +202 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/LICENSE +43 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/README.md +236 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +437 -6
- package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +3 -4
- package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +842 -5
- package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +226 -10
- package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +365 -1
- package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +33 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +26 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BDSG/paragraphs.md +62 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BFSG/paragraphs.md +85 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BGB/paragraphs.md +112 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DDG/paragraphs.md +71 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DSGVO/articles.md +182 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/articles.md +108 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/articles.md +131 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/HGB-AO/paragraphs.md +61 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/INDEX.md +93 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TDDDG/paragraphs.md +67 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/UWG/paragraphs.md +117 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/VSBG/paragraphs.md +57 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +22 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/INDEX.md +122 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/mistral-eu.md +123 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/openai-dpa.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/nextauth-tom.md +120 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/supabase-auth-tom.md +104 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/proxy-csp-pattern.md +93 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/payment/stripe-pci-tom.md +121 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/tracking/plausible-pattern.md +107 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/AffiliateDisclaimer.tsx.example +54 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/COMPLIANCE-AUDIT-TRAIL-template.md +95 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSE-Section-UGC.md.example +77 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSFA-template.md +76 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/LostFoundReportForm-consent.tsx.example +126 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/README.md +33 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/UmamiScript.tsx.example +64 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/VVT-template.md +60 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-cron.ts.example +52 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-workflow.yml.example +47 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/proxy-strict-dynamic.ts.example +80 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/security.txt.example +26 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/scripts/health-check.sh +120 -0
- package/skills/defensive/aegis-native/rls-defense/SKILL.md +110 -0
- package/skills/defensive/aegis-native/tenant-isolation-defense/SKILL.md +26 -0
- package/skills/foundation/_INDEX.md +73 -0
- package/skills/foundation/aegis-native/aegis-audit/SKILL.md +194 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-1-headers.md +138 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-2-html.md +153 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-3-impressum.md +159 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-4-dse.md +178 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-5-cookie.md +180 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-6-branche.md +204 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-7-code-cross-check.md +212 -0
- package/skills/foundation/aegis-native/aegis-audit/references/layer-8-schadens-diagnose.md +232 -0
- package/skills/foundation/aegis-native/aegis-customer-build/SKILL.md +232 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-1-recon.md +147 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-2-architecture.md +164 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-3-component-build.md +231 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-4-content.md +196 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-5-integration.md +273 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-6-mid-audit.md +200 -0
- package/skills/foundation/aegis-native/aegis-customer-build/references/phase-7-final-verify.md +258 -0
- package/skills/foundation/aegis-native/aegis-handover-writer/SKILL.md +128 -0
- package/skills/foundation/aegis-native/aegis-module-builder/SKILL.md +255 -0
- package/skills/foundation/aegis-native/aegis-orchestrator/SKILL.md +229 -0
- package/skills/foundation/aegis-native/aegis-quality-gates/SKILL.md +182 -0
- package/skills/foundation/aegis-native/aegis-skill-creator/SKILL.md +223 -0
- package/skills/foundation/aegis-native/aegis-skill-creator/references/hard-constraint-template.md +213 -0
- package/skills/foundation/aegis-native/aegis-skill-creator/references/skillforge-methodology.md +220 -0
- package/skills/foundation/aegis-native/dsgvo-compliance/SKILL.md +185 -0
- package/skills/foundation/aegis-native/dsgvo-compliance/references/art-13-15-templates.md +309 -0
- package/skills/foundation/aegis-native/dsgvo-compliance/references/datenpanne-runbook.md +291 -0
- package/skills/offensive/matty-fork/cicd-redteam/SKILL.md +531 -0
- package/skills/offensive/matty-fork/cloud-security/SKILL.md +106 -0
- package/skills/offensive/matty-fork/container-escape/SKILL.md +174 -0
- package/skills/offensive/matty-fork/mobile-pentester/SKILL.md +357 -0
- package/skills/offensive/matty-fork/subdomain-takeover/SKILL.md +154 -0
- package/skills/osint/elementalsouls-fork/offensive-osint/README.md +92 -0
- package/skills/osint/elementalsouls-fork/offensive-osint/SKILL.md +4177 -0
- package/skills/osint/elementalsouls-fork/osint-methodology/README.md +66 -0
- package/skills/osint/elementalsouls-fork/osint-methodology/SKILL.md +1695 -0
- package/sbom.cdx.json +0 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Layer 3 Reference — Impressum (DDG §5)
|
|
2
|
+
|
|
3
|
+
Layer 3 verifies the Impressum (legal notice) per DDG §5 (formerly TMG §5, renamed 2024-05-14 with TDDDG enactment). Catches: missing pflichtangaben, broken links, browser-vs-bot-walled pages. **Time:** ~3-5 min per target.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pflichtangaben Checklist (DDG §5)
|
|
8
|
+
|
|
9
|
+
| # | Pflichtangabe | Field-name | Required when |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| 1 | Name + Anschrift | Geschäftsbezeichnung + Straße + PLZ + Ort | always (geschäftsmäßig) |
|
|
12
|
+
| 2 | Vertretungsberechtigter | Geschäftsführer (bei juristischen Personen) | for GmbH/AG/UG/etc. |
|
|
13
|
+
| 3 | Kontakt: E-Mail + Telefon | E-Mail + Tel. | always |
|
|
14
|
+
| 4 | Handelsregister | HRB-Nummer + Registergericht | for handelsregister-pflichtige Rechtsformen |
|
|
15
|
+
| 5 | Umsatzsteuer-ID | USt-IdNr. (`DE...`) | when § 27a UStG applies |
|
|
16
|
+
| 6 | Wirtschafts-ID | W-IdNr. | when applicable |
|
|
17
|
+
| 7 | Aufsichtsbehörde | Name + Adresse | for state-licensed industries (Anwalt, Arzt, Architekt, Steuerberater, ...) |
|
|
18
|
+
| 8 | Berufsbezeichnung + Kammer | Bezeichnung + verleihender Staat + Kammer | for regulated professions |
|
|
19
|
+
| 9 | Berufshaftpflicht | Versicherer + räumlicher Geltungsbereich | for regulated professions (Anwalt, Arzt, ...) |
|
|
20
|
+
| 10 | Online-Streitbeilegung Hinweis | Link zu ec.europa.eu/consumers/odr | for B2C with online-business |
|
|
21
|
+
| 11 | Verbraucherstreitbeilegung Hinweis | Bereit-/Nicht-Bereit-Erklärung | for B2C |
|
|
22
|
+
| 12 | Inhaltlich Verantwortlicher (§ 18 Abs. 2 MStV) | Name + Anschrift | for journalistic-redaktional Angebote |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Probe Pattern
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Resolve impressum-URL
|
|
30
|
+
IMPRESSUM_URL=$(node -e "
|
|
31
|
+
const html = require('fs').readFileSync('/tmp/audit-html-static.html', 'utf-8');
|
|
32
|
+
const match = html.match(/href=['\"]([^'\"]*impressum[^'\"]*)['\"]/i);
|
|
33
|
+
console.log(match ? new URL(match[1], '$TARGET').href : '');
|
|
34
|
+
")
|
|
35
|
+
|
|
36
|
+
if [ -z "$IMPRESSUM_URL" ]; then
|
|
37
|
+
echo "L3-IMPRESSUM-NO-FOOTER-LINK: KRITISCH"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Fetch with browser-UA (some sites bot-wall)
|
|
42
|
+
curl -sL -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" "$IMPRESSUM_URL" > /tmp/audit-impressum.html
|
|
43
|
+
|
|
44
|
+
# Or fall-back to Playwright
|
|
45
|
+
[ "$(wc -c < /tmp/audit-impressum.html)" -lt 1000 ] && {
|
|
46
|
+
npx -y playwright-core@latest <<EOF | tee /tmp/audit-impressum.html
|
|
47
|
+
const { chromium } = require('playwright-core');
|
|
48
|
+
(async () => {
|
|
49
|
+
const b = await chromium.launch();
|
|
50
|
+
const p = await (await b.newContext()).newPage();
|
|
51
|
+
await p.goto('$IMPRESSUM_URL', { waitUntil: 'networkidle' });
|
|
52
|
+
console.log(await p.content());
|
|
53
|
+
await b.close();
|
|
54
|
+
})();
|
|
55
|
+
EOF
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Per-Field Detection Patterns
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Geschäftsbezeichnung + Anschrift (presence check)
|
|
65
|
+
grep -E '(GmbH|UG|AG|e\.K\.|[A-ZÄÖÜ][a-zäöü]+ [A-ZÄÖÜ][a-zäöü]+)' /tmp/audit-impressum.html | head -3
|
|
66
|
+
grep -E '\b[0-9]{5}\b' /tmp/audit-impressum.html # German postal code
|
|
67
|
+
|
|
68
|
+
# E-Mail + Telefon
|
|
69
|
+
grep -oE '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' /tmp/audit-impressum.html | head -3
|
|
70
|
+
grep -oE '\+?49[ /-]?[0-9 /-]{7,}' /tmp/audit-impressum.html | head -3
|
|
71
|
+
|
|
72
|
+
# USt-IdNr.
|
|
73
|
+
grep -oE 'DE[ ]?[0-9]{9}' /tmp/audit-impressum.html
|
|
74
|
+
|
|
75
|
+
# Handelsregister
|
|
76
|
+
grep -oE 'HRB[ ]?[0-9]+' /tmp/audit-impressum.html
|
|
77
|
+
grep -oE 'Amtsgericht [A-ZÄÖÜ][a-zäöü]+' /tmp/audit-impressum.html
|
|
78
|
+
|
|
79
|
+
# OS-Streitbeilegung Link
|
|
80
|
+
grep -E 'ec\.europa\.eu/consumers/odr' /tmp/audit-impressum.html
|
|
81
|
+
|
|
82
|
+
# Verbraucherstreitbeilegung Hinweis
|
|
83
|
+
grep -E '(Verbraucherstreitbeilegung|Streitbeilegungsverfahren)' /tmp/audit-impressum.html
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Severity Matrix
|
|
89
|
+
|
|
90
|
+
| Missing field | Severity |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Geschäftsbezeichnung + Anschrift | KRITISCH |
|
|
93
|
+
| Vertretungsberechtigter (when GmbH/AG/UG) | KRITISCH |
|
|
94
|
+
| E-Mail | KRITISCH |
|
|
95
|
+
| Telefon | HOCH (some courts accept E-Mail-only; abmahn-risk) |
|
|
96
|
+
| HRB + Registergericht (when handelsregister-pflichtig) | KRITISCH |
|
|
97
|
+
| USt-IdNr. (when § 27a UStG applies) | KRITISCH |
|
|
98
|
+
| Aufsichtsbehörde (for regulated industries) | KRITISCH |
|
|
99
|
+
| Berufshaftpflicht (for regulated professions) | KRITISCH |
|
|
100
|
+
| OS-Streitbeilegung Link (when B2C online) | HOCH |
|
|
101
|
+
| Verbraucherstreitbeilegung Hinweis (B2C) | MITTEL |
|
|
102
|
+
| Inhaltlich Verantwortlicher (when journalistic) | KRITISCH |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Cross-Check: Code-Repo (when Layer 7 enabled)
|
|
107
|
+
|
|
108
|
+
If aegis-audit runs against a local repo (Layer 7 enabled), cross-check:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# Find impressum data in code
|
|
112
|
+
find . -path ./node_modules -prune -o -type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.json' -o -name '*.md' \) -print | xargs grep -lE 'impressum|HRB|USt-IdNr' 2>/dev/null
|
|
113
|
+
|
|
114
|
+
# Verify code-data matches rendered-data
|
|
115
|
+
# E.g., site says HRB 12345 but code has HRB 67890 — drift
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
If drift detected → L3-IMPRESSUM-CODE-DRIFT: HOCH (data inconsistency).
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Court-Decision References
|
|
123
|
+
|
|
124
|
+
For findings, cite court-decisions where applicable:
|
|
125
|
+
|
|
126
|
+
- KG Berlin 2010-04-21 (5 W 39/10) — vollständiger Name + Anschrift Pflicht
|
|
127
|
+
- LG Düsseldorf 2008-05-21 (12 O 250/07) — Telefon Pflicht für unmittelbare Kontaktaufnahme
|
|
128
|
+
- EuGH 2008-10-16 (C-298/07) — § 5 TMG (= jetzt DDG §5) ist Verbraucherinformations-Pflicht; B2B + B2C
|
|
129
|
+
- BGH 2007-09-20 (I ZR 88/05) — Impressum 2-clicks-rule (vom Footer aus erreichbar)
|
|
130
|
+
- LG München I 2022-01-20 (3 O 17493/20) — Google-Fonts (cross-layer with L4 + L5)
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Findings Format
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
- id: L3-IMPRESSUM-VAT-MISSING
|
|
138
|
+
layer: 3
|
|
139
|
+
severity: KRITISCH
|
|
140
|
+
evidence:
|
|
141
|
+
url: <impressum-url>
|
|
142
|
+
field: USt-IdNr.
|
|
143
|
+
matches: []
|
|
144
|
+
detection: "no DE-prefixed VAT-ID found in /impressum HTML"
|
|
145
|
+
recommendation: "Add 'Umsatzsteuer-Identifikationsnummer: DE123456789' under § 27a UStG section"
|
|
146
|
+
citation: "DDG § 5 Abs. 1 Nr. 6, § 27a UStG"
|
|
147
|
+
abmahn_risk: "€500-2000 per finding (industry × visibility-dependent)"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Anti-Patterns specific to Layer 3
|
|
153
|
+
|
|
154
|
+
- ❌ Reporting "USt-IdNr. missing" for a Kleinunternehmer (§ 19 UStG) — only § 27a UStG businesses need to publish.
|
|
155
|
+
- ❌ Reporting "OS-Streitbeilegung missing" for B2B-only sites — only B2C requires this.
|
|
156
|
+
- ❌ Skipping browser-UA fallback — many sites bot-wall scanners; without browser-UA the impressum returns 403.
|
|
157
|
+
- ❌ Inferring "Aufsichtsbehörde missing" without first detecting industry — non-regulated industries don't need this.
|
|
158
|
+
- ❌ Reporting on Inhaltlich-Verantwortlicher (§ 18 MStV) for non-journalistic sites — pure commercial sites don't need.
|
|
159
|
+
- ❌ Reporting "missing Berufshaftpflicht" for unregulated professions — pflicht only for Anwalt / Arzt / Steuerberater / Architekt.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Layer 4 Reference — DSE (Datenschutzerklärung, DSGVO Art. 13/14)
|
|
2
|
+
|
|
3
|
+
Layer 4 verifies the Datenschutzerklärung against DSGVO Art. 13 (Informationspflicht bei Erhebung beim Betroffenen) + Art. 14 (Erhebung bei Dritten) + Drittlandtransfer-Konformität (Schrems-II / SCC). **Time:** ~5-10 min per target.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Art. 13 Pflichtangaben Checklist
|
|
8
|
+
|
|
9
|
+
| # | Field | Severity if missing |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| 1 | Verantwortlicher (Name + Anschrift) | KRITISCH |
|
|
12
|
+
| 2 | Vertreter in der EU (when applicable) | HOCH |
|
|
13
|
+
| 3 | Datenschutzbeauftragter (when applicable per Art. 37) | HOCH (when pflicht) |
|
|
14
|
+
| 4 | Verarbeitungszwecke + Rechtsgrundlage (Art. 6 / Art. 9) | KRITISCH |
|
|
15
|
+
| 5 | Berechtigte Interessen (when Art. 6 Abs. 1 lit. f) | HOCH |
|
|
16
|
+
| 6 | Empfänger / Empfängerkategorien | HOCH |
|
|
17
|
+
| 7 | Drittlandtransfer + Schutzgarantien | KRITISCH (when transfer happens but DSE absent) |
|
|
18
|
+
| 8 | Speicherdauer / Löschkonzept | HOCH |
|
|
19
|
+
| 9 | Betroffenenrechte (Art. 15-22) | KRITISCH |
|
|
20
|
+
| 10 | Beschwerderecht bei Aufsichtsbehörde | HOCH |
|
|
21
|
+
| 11 | Pflicht zur Bereitstellung + Folgen | MITTEL |
|
|
22
|
+
| 12 | Automatisierte Entscheidung / Profiling | HOCH (when applicable) |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Probe Pattern
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Resolve DSE-URL (often /datenschutz, /privacy, /datenschutzerklaerung)
|
|
30
|
+
DSE_URL=$(node -e "
|
|
31
|
+
const html = require('fs').readFileSync('/tmp/audit-html-static.html', 'utf-8');
|
|
32
|
+
const match = html.match(/href=['\"]([^'\"]*(datenschutz|privacy)[^'\"]*)['\"]/i);
|
|
33
|
+
console.log(match ? new URL(match[1], '$TARGET').href : '');
|
|
34
|
+
")
|
|
35
|
+
|
|
36
|
+
curl -sL -A "Mozilla/5.0" "$DSE_URL" > /tmp/audit-dse.html
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Per-Field Detection Patterns
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Verantwortlicher (matches typical phrasing)
|
|
45
|
+
grep -E 'Verantwortliche[r]?\s+i[mn]?\s+Sinne' /tmp/audit-dse.html
|
|
46
|
+
|
|
47
|
+
# Datenschutzbeauftragter
|
|
48
|
+
grep -iE '(Datenschutzbeauftragte[rn]|Data Protection Officer|DSB)' /tmp/audit-dse.html
|
|
49
|
+
|
|
50
|
+
# Verarbeitungszwecke (look for Art. 6 references)
|
|
51
|
+
grep -E 'Art\.\s*6\s*Abs\.\s*1\s*lit\.\s*[abcdef]' /tmp/audit-dse.html
|
|
52
|
+
|
|
53
|
+
# Drittlandtransfer (US, GB post-Brexit)
|
|
54
|
+
grep -iE '(Drittland|USA|United States|Standardvertragsklauseln|SCC|Privacy Shield|TIA)' /tmp/audit-dse.html
|
|
55
|
+
|
|
56
|
+
# Speicherdauer
|
|
57
|
+
grep -iE '(Speicherdauer|Löschkonzept|Aufbewahrungsfrist)' /tmp/audit-dse.html
|
|
58
|
+
|
|
59
|
+
# Betroffenenrechte (Art. 15-22)
|
|
60
|
+
grep -E 'Art\.\s*1[5-9]|Art\.\s*2[0-2]' /tmp/audit-dse.html
|
|
61
|
+
grep -iE '(Auskunftsrecht|Berichtigung|Löschung|Einschränkung|Datenübertragbarkeit|Widerspruch)' /tmp/audit-dse.html
|
|
62
|
+
|
|
63
|
+
# Beschwerderecht
|
|
64
|
+
grep -iE '(Beschwerderecht|Aufsichtsbehörde|Datenschutzbeauftragte des Landes)' /tmp/audit-dse.html
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Drittland-Transfer Detection (cross-check Layer 1 + Layer 5)
|
|
70
|
+
|
|
71
|
+
Layer 4 cross-references with Layer 1 (CDN / 3rd-party domains in HTTP-headers) + Layer 5 (cookies set by 3rd-party trackers) to detect:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# 3rd-party domains active on the page (from Layer 1 / Layer 5)
|
|
75
|
+
3p_domains=$(grep -oE 'https?://[^/]+' /tmp/audit-html-dynamic.html | sort -u | grep -v "$TARGET_DOMAIN")
|
|
76
|
+
|
|
77
|
+
# For each 3rd-party, check if DSE mentions it
|
|
78
|
+
for domain in $3p_domains; do
|
|
79
|
+
if grep -q "$domain" /tmp/audit-dse.html; then
|
|
80
|
+
echo "L4-DSE-MENTIONS: $domain ✓"
|
|
81
|
+
else
|
|
82
|
+
echo "L4-DSE-3P-NOT-MENTIONED: $domain (HOCH)"
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
US-headquartered 3rd-parties (Google, Meta, Cloudflare, AWS) trigger Drittlandtransfer concerns. DSE MUST mention:
|
|
88
|
+
|
|
89
|
+
- The 3rd-party (by name or category)
|
|
90
|
+
- The country of transfer
|
|
91
|
+
- The schutzgarantien (SCC + TIA per Schrems-II requirements post-2020-07-16 EuGH C-311/18)
|
|
92
|
+
|
|
93
|
+
If 3rd-party transfer happens AND DSE doesn't address it → KRITISCH (Schrems-II).
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Common Schrems-II Findings
|
|
98
|
+
|
|
99
|
+
| 3rd-party | DSE-required addressing |
|
|
100
|
+
|---|---|
|
|
101
|
+
| Google Fonts (when loaded from fonts.googleapis.com) | KRITISCH if not local-bundled (LG München I 2022-01-20 3 O 17493/20) |
|
|
102
|
+
| Google Analytics (without IP-anonymization + consent) | KRITISCH |
|
|
103
|
+
| Google Maps embed (without consent OR static-image-fallback) | HOCH |
|
|
104
|
+
| reCAPTCHA v3 (silent tracking) | KRITISCH |
|
|
105
|
+
| Cloudflare (when used as CDN with EU-traffic) | MITTEL (DPA exists; SCC referenced) |
|
|
106
|
+
| AWS / Azure / GCP (US-region) | HOCH (require SCC-DPA) |
|
|
107
|
+
| Vercel (US-hosted) | MITTEL (Vercel offers DPA) |
|
|
108
|
+
| Mailchimp / Sendinblue / Brevo | HOCH (US/EU split, requires SCC) |
|
|
109
|
+
|
|
110
|
+
For each, check if DSE has the required transfer-section AND processor-AVV (Auftragsverarbeitung) listing.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## AVV-List Detection
|
|
115
|
+
|
|
116
|
+
DSGVO Art. 28 requires AVV (Auftragsverarbeitung-Vertrag) for every processor handling personal data. DSE should reference:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
grep -iE '(Auftragsverarbeitung|Art\.\s*28|AVV)' /tmp/audit-dse.html
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For each 3rd-party from Layer 1 + 5: AVV must exist (signed contract); DSE should mention by name.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Severity Matrix
|
|
127
|
+
|
|
128
|
+
| Missing | Severity |
|
|
129
|
+
|---|---|
|
|
130
|
+
| Verantwortlicher (Art. 13 Abs. 1 lit. a) | KRITISCH |
|
|
131
|
+
| Verarbeitungszwecke + Rechtsgrundlage (Art. 13 Abs. 1 lit. c-d) | KRITISCH |
|
|
132
|
+
| Betroffenenrechte (Art. 15-22) | KRITISCH |
|
|
133
|
+
| Drittlandtransfer + SCC + TIA (when transfer happens) | KRITISCH |
|
|
134
|
+
| Speicherdauer (Art. 13 Abs. 2 lit. a) | HOCH |
|
|
135
|
+
| Empfänger (Art. 13 Abs. 1 lit. e) | HOCH |
|
|
136
|
+
| Beschwerderecht (Art. 13 Abs. 2 lit. d) | HOCH |
|
|
137
|
+
| Datenschutzbeauftragter (when pflicht per Art. 37) | HOCH |
|
|
138
|
+
| Vertreter in der EU (when ext.-EU controller) | HOCH |
|
|
139
|
+
| Automatisierte Entscheidung (when applicable) | HOCH |
|
|
140
|
+
| Pflicht zur Bereitstellung (Art. 13 Abs. 2 lit. e) | MITTEL |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Court-Decision References
|
|
145
|
+
|
|
146
|
+
- EuGH 2020-07-16 (C-311/18) — Schrems-II — invalidation of Privacy Shield; SCC + TIA required
|
|
147
|
+
- LG München I 2022-01-20 (3 O 17493/20) — Google-Fonts via Google CDN = Drittlandtransfer ohne Rechtsgrundlage; 100€ Schadensersatz pro Betroffenem
|
|
148
|
+
- BGH 2020-05-28 (I ZR 7/16) — Cookie-Banner BGB
|
|
149
|
+
- OLG Düsseldorf 2019-03-26 (I-20 U 75/18) — DSE als wettbewerbsrechtliche Pflicht (UWG abmahnbar)
|
|
150
|
+
- EDSA Recommendations 01/2020 — Schutzgarantien-Beurteilung TIA-Methodik
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Findings Format
|
|
155
|
+
|
|
156
|
+
```yaml
|
|
157
|
+
- id: L4-DSE-DRITTLAND-MISSING
|
|
158
|
+
layer: 4
|
|
159
|
+
severity: KRITISCH
|
|
160
|
+
evidence:
|
|
161
|
+
dse_url: <dse-url>
|
|
162
|
+
detected_3p: ["fonts.googleapis.com", "www.google-analytics.com"]
|
|
163
|
+
dse_mentions_drittland: false
|
|
164
|
+
dse_mentions_scc: false
|
|
165
|
+
recommendation: "Add Drittlandtransfer-section listing US-3rd-parties (Google Fonts, GA), reference SCC + TIA per Schrems-II"
|
|
166
|
+
citation: "DSGVO Art. 13 Abs. 1 lit. f, Art. 46; EuGH C-311/18 (Schrems-II); LG München I 3 O 17493/20"
|
|
167
|
+
abmahn_risk: "€2000-15000 per Betroffenem (LG München-Linie); aggregated risk per visitor-month"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Anti-Patterns specific to Layer 4
|
|
173
|
+
|
|
174
|
+
- ❌ Reporting "Drittlandtransfer missing" without verifying transfer actually happens — first detect 3rd-parties via Layer 1 + 5.
|
|
175
|
+
- ❌ Skipping AVV-cross-check — Art. 28 AVV is separate from Art. 13 DSE.
|
|
176
|
+
- ❌ Reporting "DSB missing" for small businesses (< 20 employees handling personal data routinely) — Art. 37 thresholds apply.
|
|
177
|
+
- ❌ Inferring DSE-completeness from word-count — short DSE can be complete; long DSE can miss fields.
|
|
178
|
+
- ❌ Reporting on automatisierte Entscheidung when site has no profiling — only applies when profiling/decisions actually happen.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Layer 5 Reference — Cookie + Consent (TTDSG/TDDDG §25)
|
|
2
|
+
|
|
3
|
+
Layer 5 verifies cookie-banner + consent-flow against TTDSG/TDDDG §25 (formerly TTDSG, renamed 2024-05-14 with TDDDG enactment) + BGH cookie-decision (2020-05-28) + EU-Cookie-Banner-Guidelines. **Time:** ~5-10 min per target.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Probe Pattern
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Fresh page-load (no prior consent-cookies)
|
|
11
|
+
mkdir -p /tmp/audit-cookie-jar
|
|
12
|
+
rm -f /tmp/audit-cookie-jar/*
|
|
13
|
+
curl -sL -A "Mozilla/5.0" -c /tmp/audit-cookie-jar/cookies.txt "$TARGET" > /tmp/audit-fresh.html
|
|
14
|
+
|
|
15
|
+
# What cookies were set BEFORE consent?
|
|
16
|
+
cat /tmp/audit-cookie-jar/cookies.txt
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then a Playwright-based probe to detect dynamic cookies (set by JS) AND verify the consent-banner appears + works:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx -y playwright-core@latest <<EOF
|
|
23
|
+
const { chromium } = require('playwright-core');
|
|
24
|
+
(async () => {
|
|
25
|
+
const b = await chromium.launch();
|
|
26
|
+
const ctx = await b.newContext();
|
|
27
|
+
const p = await ctx.newPage();
|
|
28
|
+
|
|
29
|
+
// Capture all requests + responses
|
|
30
|
+
const requests = [];
|
|
31
|
+
p.on('request', r => requests.push({ url: r.url(), type: r.resourceType() }));
|
|
32
|
+
|
|
33
|
+
// Navigate
|
|
34
|
+
await p.goto('$TARGET', { waitUntil: 'networkidle' });
|
|
35
|
+
|
|
36
|
+
// Capture cookies pre-consent
|
|
37
|
+
const preConsentCookies = await ctx.cookies();
|
|
38
|
+
|
|
39
|
+
// Check for consent-banner
|
|
40
|
+
const bannerSelector = 'div[id*="cookie"], div[class*="cookie"], div[class*="consent"]';
|
|
41
|
+
const banner = await p.$(bannerSelector);
|
|
42
|
+
const bannerHasBoth = banner ? await banner.evaluate(el => {
|
|
43
|
+
const text = el.innerText.toLowerCase();
|
|
44
|
+
return text.includes('akzeptieren') && (text.includes('ablehnen') || text.includes('reject'));
|
|
45
|
+
}) : false;
|
|
46
|
+
|
|
47
|
+
console.log(JSON.stringify({
|
|
48
|
+
preConsentCookies,
|
|
49
|
+
requests: requests.length,
|
|
50
|
+
bannerPresent: !!banner,
|
|
51
|
+
bannerHasBoth,
|
|
52
|
+
}, null, 2));
|
|
53
|
+
|
|
54
|
+
await b.close();
|
|
55
|
+
})();
|
|
56
|
+
EOF > /tmp/audit-cookie-probe.json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## TTDSG/TDDDG §25 Pre-Consent-Tracker Detection
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Pre-consent cookies (any technically-non-required cookie set before consent = §25 violation)
|
|
65
|
+
pre_count=$(jq -r '.preConsentCookies | length' /tmp/audit-cookie-probe.json)
|
|
66
|
+
|
|
67
|
+
# Filter for tracking-cookies (heuristic: 3rd-party domain or known-tracking-pattern)
|
|
68
|
+
tracking_pre=$(jq -r '.preConsentCookies[] | select(.domain | test("google|facebook|meta|doubleclick|hotjar|matomo|fathom|plausible|gtag|gads|fb_pixel|tiktok"))' /tmp/audit-cookie-probe.json)
|
|
69
|
+
|
|
70
|
+
[ -n "$tracking_pre" ] && echo "L5-PRE-CONSENT-TRACKER: KRITISCH"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Banner-Pattern Compliance
|
|
76
|
+
|
|
77
|
+
| Check | Severity if violated |
|
|
78
|
+
|---|---|
|
|
79
|
+
| Banner appears on first page-load | KRITISCH (no banner = no consent collected) |
|
|
80
|
+
| Banner has equal-prominence "Accept" + "Reject all" | KRITISCH (BGH I ZR 7/16 — dark-pattern) |
|
|
81
|
+
| Banner is granular (per-vendor opt-in for non-essential) | HOCH (BGH 2020-05-28 — global-opt-in invalid) |
|
|
82
|
+
| Banner appears BEFORE any tracking-cookie set | KRITISCH (TTDSG §25) |
|
|
83
|
+
| User can opt-out at any time (e.g., footer-link to /cookies/einstellungen) | HOCH |
|
|
84
|
+
| Pre-checked checkboxes for opt-in | KRITISCH (DSGVO Art. 7 Abs. 2 — explicit consent required) |
|
|
85
|
+
| Bundling consent (e.g., AGB + Cookie consent in one checkbox) | HOCH |
|
|
86
|
+
| Continuing-to-use-site interpreted as consent | KRITISCH (BGH 2020-05-28 — mere browsing ≠ consent) |
|
|
87
|
+
| Re-prompt period reasonable (≥ 6 months between prompts unless settings changed) | LOW |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Granular vs Global
|
|
92
|
+
|
|
93
|
+
| Pattern | Compliance |
|
|
94
|
+
|---|---|
|
|
95
|
+
| "Akzeptieren" + "Ablehnen" only (no granular) | HOCH (BGH-line — granular better) |
|
|
96
|
+
| "Akzeptieren" + "Ablehnen" + per-vendor toggle | OK (granular) |
|
|
97
|
+
| "Akzeptieren" + "Einstellungen" (where settings = granular) | OK if reachable in 1 click |
|
|
98
|
+
| "Akzeptieren" + tiny "Ablehnen" (visual asymmetry) | KRITISCH (dark-pattern, BGH-line) |
|
|
99
|
+
| "Akzeptieren" only (no reject-button on first banner) | KRITISCH |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Consent-Mode-v2 (Google) Detection
|
|
104
|
+
|
|
105
|
+
If site uses Google products (Analytics, Ads, Tag Manager), check for Consent-Mode-v2:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
grep -E 'gtag\(.consent.,\s*.default.|consentDefault' /tmp/audit-fresh.html
|
|
109
|
+
|
|
110
|
+
# default state should be 'denied' for ad_storage, ad_user_data, ad_personalization, analytics_storage
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Default-`granted` for analytics_storage = pre-consent-tracking even with Consent-Mode = KRITISCH.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Cookie-Categories Mapping
|
|
118
|
+
|
|
119
|
+
For each cookie set on the site, classify:
|
|
120
|
+
|
|
121
|
+
| Category | Consent-required | Examples |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| Strictly necessary | NO | session-id, csrf-token, cookie-consent-state |
|
|
124
|
+
| Functional | Implicitly OK | language-preference, theme |
|
|
125
|
+
| Analytics (anonymized) | YES (per §25) | matomo (with anonymize_ip), google-analytics-with-anonymize |
|
|
126
|
+
| Marketing / Advertising | YES (explicit, granular) | _ga, _gid (without anonymize_ip), _fbp, fr, doubleclick |
|
|
127
|
+
| Third-party content | YES (depending on data) | YouTube embed, Google Maps with API-key |
|
|
128
|
+
|
|
129
|
+
If a cookie is "Strictly necessary" — must be on a justified business-need; not just "we want it".
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Cookie-Banner-Library Detection
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Common libraries used on DACH sites
|
|
137
|
+
grep -iE '(usercentrics|cookiefirst|cookieyes|borlabs|webcm|consent-manager|onetrust|cookiepro|privacymanager|cookieinformation|complianz|iubenda)' /tmp/audit-fresh.html | head -3
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If a recognized library is used — check its current-version compliance (via library-CHANGELOG cross-reference; e.g., Borlabs Cookie ≥ 2.2.0 is compliant; older versions had known dark-pattern bugs).
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## CMP IAB-Framework Detection
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# IAB-TCF-API presence
|
|
148
|
+
grep -E '__tcfapi\(|TCF_API|cmp\.openWindow' /tmp/audit-fresh.html
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
If TCF-v2 used — verify Vendor-List up-to-date + Purposes match what's actually loaded.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Findings Format
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
- id: L5-PRE-CONSENT-TRACKER
|
|
159
|
+
layer: 5
|
|
160
|
+
severity: KRITISCH
|
|
161
|
+
evidence:
|
|
162
|
+
target: <target>
|
|
163
|
+
pre_consent_cookies: ["_ga", "_gid", "_fbp"]
|
|
164
|
+
banner_present: true
|
|
165
|
+
banner_appears_after_load: true # but cookies were already set
|
|
166
|
+
recommendation: "Move all tracking-cookies behind cookie-banner consent. Use Google Consent-Mode-v2 with default='denied'. Verify with fresh page-load + cookies.txt empty."
|
|
167
|
+
citation: "TTDSG/TDDDG §25 Abs. 1; DSGVO Art. 7 Abs. 1; BGH I ZR 7/16 (2020-05-28); EuGH C-673/17 (Planet49)"
|
|
168
|
+
abmahn_risk: "€500-5000 per finding (industry × visibility); composite with L4-DSE-DRITTLAND-MISSING bumps to €5000-15000"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Anti-Patterns specific to Layer 5
|
|
174
|
+
|
|
175
|
+
- ❌ Probing with stale cookie-jar — always use fresh /tmp/audit-cookie-jar.
|
|
176
|
+
- ❌ Skipping Playwright probe "because curl is enough" — JS-set cookies invisible to curl.
|
|
177
|
+
- ❌ Reporting "no banner" for sites with technically-only cookies (no consent-required) — first verify what cookies are actually set.
|
|
178
|
+
- ❌ Marking "_ga" as KRITISCH if site uses Consent-Mode-v2 with default-denied — first check the consent-default-state.
|
|
179
|
+
- ❌ Reporting "global opt-in invalid" without checking BGH-line context — granular is preferred but global-only is HOCH not KRITISCH per current BGH-Linie.
|
|
180
|
+
- ❌ Inferring tracking-cookie from name alone — verify domain + actual purpose; some "_ga"-prefixed cookies are 1st-party-only.
|