@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.
Files changed (93) hide show
  1. package/ATTRIBUTION.md +171 -4
  2. package/CHANGELOG.md +112 -1
  3. package/README.md +27 -0
  4. package/dist/skills-loader.d.ts +43 -0
  5. package/dist/skills-loader.d.ts.map +1 -1
  6. package/dist/skills-loader.js +102 -0
  7. package/dist/skills-loader.js.map +1 -1
  8. package/package.json +1 -1
  9. package/skills/compliance/_INDEX.md +49 -0
  10. package/skills/compliance/aegis-native/brutaler-anwalt/CHANGELOG.md +202 -0
  11. package/skills/compliance/aegis-native/brutaler-anwalt/LICENSE +43 -0
  12. package/skills/compliance/aegis-native/brutaler-anwalt/README.md +236 -0
  13. package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +437 -6
  14. package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +3 -4
  15. package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +842 -5
  16. package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +226 -10
  17. package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +365 -1
  18. package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +33 -0
  19. package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +26 -0
  20. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BDSG/paragraphs.md +62 -0
  21. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BFSG/paragraphs.md +85 -0
  22. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/BGB/paragraphs.md +112 -0
  23. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DDG/paragraphs.md +71 -0
  24. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/DSGVO/articles.md +182 -0
  25. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/AI-Act-2024-1689/articles.md +108 -0
  26. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/EU-Verordnungen/DSA-2022-2065/articles.md +131 -0
  27. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/HGB-AO/paragraphs.md +61 -0
  28. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/INDEX.md +93 -0
  29. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/TDDDG/paragraphs.md +67 -0
  30. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/UWG/paragraphs.md +117 -0
  31. package/skills/compliance/aegis-native/brutaler-anwalt/references/gesetze/VSBG/paragraphs.md +57 -0
  32. package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +22 -0
  33. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/INDEX.md +122 -0
  34. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/mistral-eu.md +123 -0
  35. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/ai/openai-dpa.md +120 -0
  36. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/nextauth-tom.md +120 -0
  37. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/auth/supabase-auth-tom.md +104 -0
  38. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/nextjs/proxy-csp-pattern.md +93 -0
  39. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/payment/stripe-pci-tom.md +121 -0
  40. package/skills/compliance/aegis-native/brutaler-anwalt/references/stack-patterns/tracking/plausible-pattern.md +107 -0
  41. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/AffiliateDisclaimer.tsx.example +54 -0
  42. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/COMPLIANCE-AUDIT-TRAIL-template.md +95 -0
  43. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSE-Section-UGC.md.example +77 -0
  44. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/DSFA-template.md +76 -0
  45. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/LostFoundReportForm-consent.tsx.example +126 -0
  46. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/README.md +33 -0
  47. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/UmamiScript.tsx.example +64 -0
  48. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/VVT-template.md +60 -0
  49. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-cron.ts.example +52 -0
  50. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/data-retention-workflow.yml.example +47 -0
  51. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/proxy-strict-dynamic.ts.example +80 -0
  52. package/skills/compliance/aegis-native/brutaler-anwalt/references/templates/security.txt.example +26 -0
  53. package/skills/compliance/aegis-native/brutaler-anwalt/scripts/health-check.sh +120 -0
  54. package/skills/defensive/aegis-native/rls-defense/SKILL.md +110 -0
  55. package/skills/defensive/aegis-native/tenant-isolation-defense/SKILL.md +26 -0
  56. package/skills/foundation/_INDEX.md +73 -0
  57. package/skills/foundation/aegis-native/aegis-audit/SKILL.md +194 -0
  58. package/skills/foundation/aegis-native/aegis-audit/references/layer-1-headers.md +138 -0
  59. package/skills/foundation/aegis-native/aegis-audit/references/layer-2-html.md +153 -0
  60. package/skills/foundation/aegis-native/aegis-audit/references/layer-3-impressum.md +159 -0
  61. package/skills/foundation/aegis-native/aegis-audit/references/layer-4-dse.md +178 -0
  62. package/skills/foundation/aegis-native/aegis-audit/references/layer-5-cookie.md +180 -0
  63. package/skills/foundation/aegis-native/aegis-audit/references/layer-6-branche.md +204 -0
  64. package/skills/foundation/aegis-native/aegis-audit/references/layer-7-code-cross-check.md +212 -0
  65. package/skills/foundation/aegis-native/aegis-audit/references/layer-8-schadens-diagnose.md +232 -0
  66. package/skills/foundation/aegis-native/aegis-customer-build/SKILL.md +232 -0
  67. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-1-recon.md +147 -0
  68. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-2-architecture.md +164 -0
  69. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-3-component-build.md +231 -0
  70. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-4-content.md +196 -0
  71. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-5-integration.md +273 -0
  72. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-6-mid-audit.md +200 -0
  73. package/skills/foundation/aegis-native/aegis-customer-build/references/phase-7-final-verify.md +258 -0
  74. package/skills/foundation/aegis-native/aegis-handover-writer/SKILL.md +128 -0
  75. package/skills/foundation/aegis-native/aegis-module-builder/SKILL.md +255 -0
  76. package/skills/foundation/aegis-native/aegis-orchestrator/SKILL.md +229 -0
  77. package/skills/foundation/aegis-native/aegis-quality-gates/SKILL.md +182 -0
  78. package/skills/foundation/aegis-native/aegis-skill-creator/SKILL.md +223 -0
  79. package/skills/foundation/aegis-native/aegis-skill-creator/references/hard-constraint-template.md +213 -0
  80. package/skills/foundation/aegis-native/aegis-skill-creator/references/skillforge-methodology.md +220 -0
  81. package/skills/foundation/aegis-native/dsgvo-compliance/SKILL.md +185 -0
  82. package/skills/foundation/aegis-native/dsgvo-compliance/references/art-13-15-templates.md +309 -0
  83. package/skills/foundation/aegis-native/dsgvo-compliance/references/datenpanne-runbook.md +291 -0
  84. package/skills/offensive/matty-fork/cicd-redteam/SKILL.md +531 -0
  85. package/skills/offensive/matty-fork/cloud-security/SKILL.md +106 -0
  86. package/skills/offensive/matty-fork/container-escape/SKILL.md +174 -0
  87. package/skills/offensive/matty-fork/mobile-pentester/SKILL.md +357 -0
  88. package/skills/offensive/matty-fork/subdomain-takeover/SKILL.md +154 -0
  89. package/skills/osint/elementalsouls-fork/offensive-osint/README.md +92 -0
  90. package/skills/osint/elementalsouls-fork/offensive-osint/SKILL.md +4177 -0
  91. package/skills/osint/elementalsouls-fork/osint-methodology/README.md +66 -0
  92. package/skills/osint/elementalsouls-fork/osint-methodology/SKILL.md +1695 -0
  93. package/sbom.cdx.json +0 -1
@@ -0,0 +1,33 @@
1
+ ---
2
+ license: MIT
3
+ purpose: Anonymized teaching snippets referenced by audit-patterns.md / dsgvo.md / checklisten.md.
4
+ ---
5
+
6
+ # Templates — anonymisierte Lehrbuch-Snippets
7
+
8
+ Diese Templates sind brand-agnostische Vorlagen, die in den References als
9
+ konkrete Lehrbuch-Beispiele zitiert werden. Sie ersetzen die in fruehen
10
+ Skill-Versionen direkt eingebetteten Brand-spezifischen Snippets.
11
+
12
+ **Konvention:**
13
+ - `<placeholder>` = vom Operator zu ersetzen (z.B. `<brand>`, `<your-domain>`)
14
+ - `<...>` in Code-Snippets sind absichtlich syntactically-invalid, damit
15
+ copy-paste-Hygiene erzwungen wird
16
+ - Alle `.example`-Files sind **keine** lauffaehigen Module — Build-Tools
17
+ sollen sie ignorieren
18
+
19
+ ## Index
20
+
21
+ | Template | Referenced from | Use case |
22
+ |----------|----------------|----------|
23
+ | `DSFA-template.md` | `dsgvo.md` DSFA-Trigger | Datenschutz-Folgenabschaetzung Doc-Vorlage |
24
+ | `VVT-template.md` | `dsgvo.md` VVT | Verzeichnis Verarbeitungstaetigkeiten Vorlage |
25
+ | `COMPLIANCE-AUDIT-TRAIL-template.md` | (Skill-Output-Pattern) | Audit-Trail-Doku-Vorlage fuer eigene Audits |
26
+ | `AffiliateDisclaimer.tsx.example` | `checklisten.md` 3c | React-Component-Vorlage UWG § 5a Abs. 4 |
27
+ | `proxy-strict-dynamic.ts.example` | `audit-patterns.md` HIGH-RISK-CSP | Next.js proxy-CSP Strict-Dynamic-Pattern |
28
+ | `data-retention-cron.ts.example` | `audit-patterns.md` Phase 4 | Bearer-auth Retention-Cleanup Route |
29
+ | `data-retention-workflow.yml.example` | `audit-patterns.md` Phase 4 | GitHub Actions Cron-Trigger |
30
+ | `UmamiScript.tsx.example` | `audit-patterns.md` env-driven Tracking | env-driven Tracking-Component |
31
+ | `security.txt.example` | `audit-patterns.md` Phase 2 | RFC 9116 (kein Placeholder-Bug) |
32
+ | `DSE-Section-UGC.md.example` | `audit-patterns.md` Phase 5c | Vermisst-/Marketplace-DSE-Block |
33
+ | `LostFoundReportForm-consent.tsx.example` | `audit-patterns.md` Phase 5c | Consent-Toggle-Pattern UGC-Posts |
@@ -0,0 +1,64 @@
1
+ // MIT-License — anonymized teaching snippet for brutaler-anwalt
2
+ // References: audit-patterns.md env-driven Tracking-Component
3
+ // Pattern: env-driven Umami / Plausible / Fathom Tracking-Snippet
4
+
5
+ // File: src/components/analytics/UmamiScript.tsx
6
+ // Use: include in app/layout.tsx (root layout). Loads only after consent OR
7
+ // if the tracker is configured "cookieless + IP-anon + DNT respect".
8
+
9
+ import Script from 'next/script';
10
+
11
+ interface UmamiScriptProps {
12
+ /** override the env-default; pass site-id explicitly when SSR-safe */
13
+ websiteId?: string;
14
+ }
15
+
16
+ export function UmamiScript({ websiteId }: UmamiScriptProps) {
17
+ // 1. host: env-driven; default = your own analytics subdomain (NOT vendor-default cloud).
18
+ // NEVER hardcode a vendor cloud URL — that's a Drittland-Trigger.
19
+ const host = (
20
+ process.env.NEXT_PUBLIC_ANALYTICS_HOST ??
21
+ 'https://<your-analytics-subdomain>'
22
+ ).replace(/\/+$/, '');
23
+
24
+ // 2. site-id from env (or prop override)
25
+ const id = websiteId ?? process.env.NEXT_PUBLIC_ANALYTICS_SITE_ID;
26
+
27
+ // 3. fail-soft: no tracking if env not configured (better than fallback to default-cloud)
28
+ if (!id) {
29
+ return null;
30
+ }
31
+
32
+ return (
33
+ <Script
34
+ strategy="afterInteractive"
35
+ src={`${host}/script.js`}
36
+ data-website-id={id}
37
+ data-host-url={host}
38
+ // Privacy-Hardening: respect DNT and GPC client-side (server-side opt: track-DNT off)
39
+ data-do-not-track="true"
40
+ // Cookieless mode + IP-anonymisation are server-side settings.
41
+ // The DSE statement MUST match the actual server-config — verify with admin-panel.
42
+ async
43
+ />
44
+ );
45
+ }
46
+
47
+ // USAGE in app/layout.tsx:
48
+ //
49
+ // import { UmamiScript } from '@/components/analytics/UmamiScript';
50
+ // export default function RootLayout({ children }) {
51
+ // return (
52
+ // <html><body>{children}<UmamiScript /></body></html>
53
+ // );
54
+ // }
55
+ //
56
+ // VERIFY:
57
+ // curl -s https://<your-domain> | grep -oE 'data-host-url="[^"]+"'
58
+ // # erwarte: dein operator-eigener Analytics-Host, nie ein Vendor-Cloud-Default
59
+ //
60
+ // DSE-PFLICHT (analog dazu):
61
+ // "Wir nutzen das selbstgehostete Analyse-Tool [Tool-Name] auf <your-analytics-subdomain>.
62
+ // Verarbeitung erfolgt cookieless mit serverseitiger IP-Anonymisierung. DNT/GPC werden
63
+ // respektiert. Rechtsgrundlage: Art. 6 Abs. 1 lit. f DSGVO (berechtigtes Interesse an
64
+ // aggregierter Reichweitenmessung). Widerspruch jederzeit moeglich..."
@@ -0,0 +1,60 @@
1
+ ---
2
+ license: MIT
3
+ purpose: Generische VVT-Vorlage (Art. 30 DSGVO). KMU-best-practice.
4
+ references: dsgvo.md (VVT-Block)
5
+ sources: Art. 30 Abs. 1 DSGVO + BayLDA-VVT-Hinweise
6
+ ---
7
+
8
+ # Verzeichnis von Verarbeitungstaetigkeiten (VVT) — Vorlage
9
+
10
+ > Diese Vorlage entspricht Art. 30 Abs. 1 DSGVO. KMU mit < 250 MA und
11
+ > gelegentlicher Verarbeitung ohne Sonderkategorien sind nicht VVT-pflichtig
12
+ > (Art. 30 Abs. 5), aber BayLDA empfiehlt VVT auch fuer KMU zur Erfuellung
13
+ > Rechenschaftspflicht Art. 5 Abs. 2.
14
+
15
+ ## Stammblatt
16
+
17
+ | Feld | Wert |
18
+ |------|------|
19
+ | Verantwortlicher | `<Operator-Firma>` |
20
+ | Anschrift | `<vollstaendige-Anschrift>` |
21
+ | Vertreter (Art. 27) | `<falls EU-Drittland-Sitz>` |
22
+ | DSB | `<falls bestellt>` |
23
+ | Stand | `<YYYY-MM-DD>` |
24
+ | Version | `<vN.N>` |
25
+
26
+ ## Verarbeitungstaetigkeiten
27
+
28
+ Pro Verarbeitung ein Block.
29
+
30
+ ### VT-001: `<Bezeichnung>`
31
+
32
+ | Pflicht-Feld (Art. 30 Abs. 1) | Wert |
33
+ |------------------------------|------|
34
+ | **a) Name + Kontaktdaten Verantwortlicher** | siehe Stammblatt |
35
+ | **b) Zwecke der Verarbeitung** | `<Zweck>` (Rechtsgrundlage Art. 6 Abs. 1 lit. `<a/b/c/d/e/f>`) |
36
+ | **c) Kategorien betroffener Personen** | `<Kunden / Mitarbeiter / Lieferanten / ...>` |
37
+ | **c) Kategorien personenbezogener Daten** | `<Stammdaten / Kontaktdaten / Nutzungsdaten / besondere Kategorien>` |
38
+ | **d) Kategorien von Empfaengern** | `<intern / Auftragsverarbeiter / Drittland>` |
39
+ | **e) Drittlandtransfer** | `<keine / USA / UK / ...>` (mit Mechanismus: SCC + TIA / Adequacy / DPF) |
40
+ | **f) Speicherdauer / Loeschfristen** | `<Frist>` (gesetzlicher Anker, z.B. § 257 HGB / § 147 AO) |
41
+ | **g) Allgemeine Beschreibung TOMs** | siehe `<TOMs-Doku-Verweis>` |
42
+
43
+ ### VT-002: `<naechste Verarbeitung>`
44
+
45
+ (analog)
46
+
47
+ ## Auftragsverarbeiter (Art. 28)
48
+
49
+ | Auftragsverarbeiter | Zweck | AVV-Status | Drittland | Standort |
50
+ |---------------------|-------|-----------|-----------|----------|
51
+ | `<Anbieter>` | `<Zweck>` | `<abgeschlossen YYYY-MM-DD>` | `<DE/EU/USA>` | `<Region>` |
52
+
53
+ ## Review
54
+
55
+ VVT bei wesentlichen Aenderungen sofort updaten, ansonsten jaehrlich.
56
+ Naechstes Review: `<YYYY-MM-DD>`.
57
+
58
+ ---
59
+
60
+ *Disclaimer: technisch-indikative Vorlage, keine Rechtsberatung i.S.d. § 2 RDG.*
@@ -0,0 +1,52 @@
1
+ // MIT-License — anonymized teaching snippet for brutaler-anwalt
2
+ // References: audit-patterns.md Phase 4 DSE-Drift-Audit Style 2 (DSE-Aussage "wir loeschen nach X")
3
+ // Pattern: Next.js API-Route mit Bearer-Auth, idempotent, audit-logged
4
+
5
+ // File: src/app/api/cron/data-retention/route.ts (Next.js App-Router)
6
+
7
+ import { NextRequest, NextResponse } from 'next/server';
8
+
9
+ const RETENTION_DAYS = Number(process.env.DATA_RETENTION_DAYS ?? '180');
10
+
11
+ export async function POST(req: NextRequest) {
12
+ // 1. Bearer-Auth — Cron-Secret aus env, nicht hardcoded
13
+ const authHeader = req.headers.get('authorization') ?? '';
14
+ const expected = `Bearer ${process.env.CRON_SECRET}`;
15
+ if (!process.env.CRON_SECRET || authHeader !== expected) {
16
+ return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
17
+ }
18
+
19
+ // 2. Compute cutoff
20
+ const cutoff = new Date(Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1000);
21
+
22
+ // 3. Delete-Logik — pro Tabelle / Collection / Bucket einzeln
23
+ const results = {
24
+ cutoff: cutoff.toISOString(),
25
+ deleted: {} as Record<string, number>,
26
+ };
27
+
28
+ try {
29
+ // Pseudocode — durch echten DB-Client ersetzen
30
+ // results.deleted.session_logs = await db.sessionLogs.deleteMany({ created_at: { lt: cutoff } });
31
+ // results.deleted.lost_found_posts = await db.lostFoundPosts.deleteMany({ expires_at: { lt: new Date() } });
32
+ // results.deleted.unverified_signups = await db.users.deleteMany({ verified: false, created_at: { lt: cutoff } });
33
+ } catch (err) {
34
+ console.error('[retention-cron] error', err);
35
+ return NextResponse.json({ error: 'cleanup-failed', details: String(err) }, { status: 500 });
36
+ }
37
+
38
+ // 4. Audit-Log — Pflicht fuer Rechenschafts-Nachweis Art. 5 Abs. 2 DSGVO
39
+ console.log(JSON.stringify({
40
+ event: 'data_retention_cleanup',
41
+ timestamp: new Date().toISOString(),
42
+ cutoff: results.cutoff,
43
+ deleted: results.deleted,
44
+ }));
45
+
46
+ return NextResponse.json(results);
47
+ }
48
+
49
+ // VERIFY:
50
+ // curl -X POST https://<your-domain>/api/cron/data-retention \
51
+ // -H "Authorization: Bearer $CRON_SECRET"
52
+ // # erwarte 200 + JSON mit deleted-counts; ohne Auth 401.
@@ -0,0 +1,47 @@
1
+ ## MIT-License — anonymized teaching snippet for brutaler-anwalt
2
+ ## References: audit-patterns.md Phase 4 DSE-Drift-Audit Style 2
3
+ ## Pattern: GitHub Actions Cron-Trigger fuer DSGVO-Retention-Cleanup
4
+
5
+ # File: .github/workflows/data-retention.yml
6
+
7
+ name: data-retention-cleanup
8
+
9
+ on:
10
+ schedule:
11
+ # tgl. 03:00 UTC = 04:00 CET (low-traffic-window)
12
+ - cron: '0 3 * * *'
13
+ workflow_dispatch: {}
14
+
15
+ jobs:
16
+ cleanup:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 5
19
+ permissions:
20
+ contents: read
21
+ steps:
22
+ - name: Trigger retention API
23
+ env:
24
+ CRON_SECRET: ${{ secrets.CRON_SECRET }}
25
+ API_URL: ${{ secrets.RETENTION_API_URL }} # https://<your-domain>/api/cron/data-retention
26
+ run: |
27
+ if [ -z "$CRON_SECRET" ] || [ -z "$API_URL" ]; then
28
+ echo "::error::CRON_SECRET or RETENTION_API_URL not set in GH secrets"
29
+ exit 1
30
+ fi
31
+ response=$(curl -sS -w "\n%{http_code}" -X POST "$API_URL" \
32
+ -H "Authorization: Bearer $CRON_SECRET" \
33
+ -H "Content-Type: application/json" \
34
+ --max-time 60)
35
+ body=$(echo "$response" | sed '$d')
36
+ status=$(echo "$response" | tail -n1)
37
+ echo "::group::API response"
38
+ echo "$body"
39
+ echo "::endgroup::"
40
+ if [ "$status" != "200" ]; then
41
+ echo "::error::retention API returned status $status"
42
+ exit 1
43
+ fi
44
+
45
+ # VERIFY in repo:
46
+ # gh workflow run data-retention-cleanup
47
+ # gh run list --workflow=data-retention-cleanup --limit 5
@@ -0,0 +1,80 @@
1
+ // MIT-License — anonymized teaching snippet for brutaler-anwalt
2
+ // References: audit-patterns.md HIGH-RISK CSP unsafe-inline Migration
3
+ // Pattern: Next.js (App Router) middleware.ts / proxy.ts mit Strict-Dynamic-CSP
4
+
5
+ // File: src/middleware.ts (oder src/proxy.ts) — Next.js 14+
6
+ // Pattern: per-request nonce → CSP-Header → propagate via x-nonce request-header.
7
+ // Layout liest x-nonce via headers().get('x-nonce') und gibt es an inline-Scripts.
8
+
9
+ import { NextRequest, NextResponse } from 'next/server';
10
+
11
+ const cspDirectives = (nonce: string) => [
12
+ `default-src 'self'`,
13
+ // Strict-Dynamic + nonce: ersetzt unsafe-inline ohne legitime inline-scripts zu brechen
14
+ `script-src 'self' 'nonce-${nonce}' 'strict-dynamic' https:`,
15
+ // Style: nonce + self; unsafe-inline weiterhin nur zugelassen wenn unvermeidbar
16
+ `style-src 'self' 'nonce-${nonce}'`,
17
+ `img-src 'self' data: https://<your-cdn-domain>`,
18
+ `font-src 'self' data:`,
19
+ // Connect: API-Endpoints + 3rd-party-Services aus DSE
20
+ `connect-src 'self' https://<api-domain> https://<analytics-host>`,
21
+ `frame-src 'self' https://<embed-domains>`,
22
+ `object-src 'none'`,
23
+ `base-uri 'self'`,
24
+ `form-action 'self'`,
25
+ `frame-ancestors 'none'`,
26
+ `upgrade-insecure-requests`,
27
+ ].join('; ');
28
+
29
+ export function middleware(req: NextRequest) {
30
+ // 1. Generate per-request nonce (16 random bytes, base64)
31
+ const nonce = btoa(crypto.getRandomValues(new Uint8Array(16)).join(''));
32
+
33
+ // 2. Forward via request-header so layout/components can read it
34
+ const requestHeaders = new Headers(req.headers);
35
+ requestHeaders.set('x-nonce', nonce);
36
+
37
+ // 3. Build response with CSP-Header
38
+ const response = NextResponse.next({ request: { headers: requestHeaders } });
39
+ response.headers.set('Content-Security-Policy', cspDirectives(nonce));
40
+
41
+ // 4. Defense-in-depth headers
42
+ response.headers.set('X-Frame-Options', 'DENY');
43
+ response.headers.set('X-Content-Type-Options', 'nosniff');
44
+ response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
45
+ response.headers.set(
46
+ 'Strict-Transport-Security',
47
+ 'max-age=63072000; includeSubDomains; preload',
48
+ );
49
+ response.headers.set(
50
+ 'Permissions-Policy',
51
+ 'camera=(), microphone=(), geolocation=(self), interest-cohort=()',
52
+ );
53
+
54
+ return response;
55
+ }
56
+
57
+ export const config = {
58
+ matcher: '/:path*',
59
+ };
60
+
61
+ // USAGE in layout.tsx:
62
+ //
63
+ // import { headers } from 'next/headers';
64
+ // export default function RootLayout({ children }) {
65
+ // const nonce = headers().get('x-nonce') ?? '';
66
+ // return (
67
+ // <html>
68
+ // <body>
69
+ // <Script id="bootstrap" nonce={nonce} strategy="beforeInteractive">
70
+ // {`/* inline bootstrap */`}
71
+ // </Script>
72
+ // {children}
73
+ // </body>
74
+ // </html>
75
+ // );
76
+ // }
77
+ //
78
+ // VERIFY:
79
+ // curl -sIS https://<your-domain> | grep -i 'content-security-policy'
80
+ // # erwarte: 'nonce-...' + 'strict-dynamic' enthalten, KEIN 'unsafe-inline'
@@ -0,0 +1,26 @@
1
+ # MIT-License — anonymized teaching snippet for brutaler-anwalt
2
+ # References: audit-patterns.md Phase 2 Public-Static-File-Audit
3
+ # Spec: RFC 9116 (https://www.rfc-editor.org/rfc/rfc9116)
4
+ #
5
+ # File: public/.well-known/security.txt
6
+ # Critical: KEINE Placeholder-Tokens (`{{...}}`, `<...>`, `YOUR_*`, `AGENT:`,
7
+ # `TODO:`, `FIXME:`) im Production-Build. Die folgenden Werte sind
8
+ # OPERATOR-VERANTWORTUNG, vor Deploy konkret zu setzen.
9
+
10
+ Contact: mailto:security@<your-domain>
11
+ Contact: https://<your-domain>/security/contact
12
+ Expires: 2027-12-31T23:59:59Z
13
+ Encryption: https://<your-domain>/.well-known/pgp-key.txt
14
+ Acknowledgments: https://<your-domain>/security/hall-of-fame
15
+ Preferred-Languages: de, en
16
+ Canonical: https://<your-domain>/.well-known/security.txt
17
+ Policy: https://<your-domain>/security/responsible-disclosure
18
+ Hiring: https://<your-domain>/karriere
19
+
20
+ # Pre-Deploy-Verify:
21
+ # curl -s https://<your-domain>/.well-known/security.txt | \
22
+ # grep -E '\{\{|<[A-Z_]+>|YOUR_|AGENT:|ASSISTANT:|TODO:|FIXME:|placeholder' && \
23
+ # echo "🔴 KRITISCH — unrendered Template" || echo "✓ clean"
24
+ #
25
+ # Expires-Datum: alle 6-12 Monate updaten. Das Datum ist hier ein Lehrbuch-Wert
26
+ # und MUSS vom Operator vor Deploy gesetzt werden. RFC 9116 verlangt < 1 Jahr.
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env bash
2
+ # brutaler-anwalt — Health-Check for skill consistency.
3
+ # Usage: bash scripts/health-check.sh
4
+ # Exit: 0 healthy · 1 issues found
5
+
6
+ set -euo pipefail
7
+
8
+ SKILL_DIR="$(cd "$(dirname "$0")/.." && pwd)"
9
+ issues=0
10
+
11
+ echo "▎ brutaler-anwalt Health-Check"
12
+ echo "▎ Skill-Dir: $SKILL_DIR"
13
+ echo
14
+
15
+ # 1. Brand-Leak-Check — operator-customizable deny-list of brand-codenames
16
+ # that must NOT appear in shipped skill content (SKILL.md / references / etc).
17
+ #
18
+ # CUSTOMIZATION: edit BRAND_PATTERN below to add your own brand-codenames
19
+ # (single-bar-separated, regex-syntax). Example: if your projects are named
20
+ # `acme-saas` and `bluefin`, set:
21
+ # BRAND_PATTERN="acme-saas|bluefin|your-internal-codename"
22
+ # Defaults are placeholder examples; replace before relying on the check.
23
+ #
24
+ # The check reads the deny-list from a gitignored sibling file when present,
25
+ # so operators can keep their real codenames out of the public skill repo.
26
+ echo "1/5 Brand-Leak-Check…"
27
+ LOCAL_DENY_FILE="$SKILL_DIR/scripts/brand-deny-list.local.txt"
28
+ if [[ -f "$LOCAL_DENY_FILE" ]]; then
29
+ # one pattern per line, joined with | for grep -E
30
+ BRAND_PATTERN=$(grep -vE '^[[:space:]]*(#|$)' "$LOCAL_DENY_FILE" | tr '\n' '|' | sed 's/|$//')
31
+ if [[ -z "$BRAND_PATTERN" ]]; then
32
+ BRAND_PATTERN="placeholder-codename-example"
33
+ fi
34
+ else
35
+ BRAND_PATTERN="placeholder-codename-example|placeholder-internal-project"
36
+ fi
37
+ brand_hits=$( (grep -rEnli "$BRAND_PATTERN" \
38
+ "$SKILL_DIR/SKILL.md" "$SKILL_DIR/README.md" "$SKILL_DIR/LICENSE" "$SKILL_DIR/CHANGELOG.md" "$SKILL_DIR/references/" 2>/dev/null || true) \
39
+ | wc -l | tr -d ' ')
40
+ if [[ "$brand_hits" == "0" ]]; then
41
+ echo " ✓ keine Brand-Leaks (Pattern: $BRAND_PATTERN)"
42
+ else
43
+ echo " ✗ $brand_hits Brand-Leak-Treffer:"
44
+ grep -rEni "$BRAND_PATTERN" \
45
+ "$SKILL_DIR/SKILL.md" "$SKILL_DIR/README.md" "$SKILL_DIR/LICENSE" "$SKILL_DIR/CHANGELOG.md" "$SKILL_DIR/references/" 2>/dev/null | head -10 || true
46
+ issues=$((issues + 1))
47
+ fi
48
+
49
+ # 2. Az.-Provenance — every entry should have a Source-URL
50
+ echo "2/5 Az.-Provenance-Check…"
51
+ az_count=$( (grep -cE "^### " "$SKILL_DIR/references/bgh-urteile.md" 2>/dev/null || echo 0) | head -1)
52
+ # Source-Verlinkung in beliebigem Markdown-Format: **Source**, "Source:", oder eingebetteter http(s)-Link.
53
+ src_count=$( (grep -cE "\*\*Source\*\*|Source:|https?://(juris|curia|dejure|openjur|rewis|edpb|gesetze-im-internet|eur-lex|bverwg|bag-urteil|nrwe|wettbewerbszentrale|noerr|twobirds|bird-bird|alro-recht)" "$SKILL_DIR/references/bgh-urteile.md" 2>/dev/null || echo 0) | head -1)
54
+ echo " Az.-Eintraege: $az_count · Source-Verlinkungen: $src_count"
55
+ if [[ "$src_count" -lt "$az_count" ]]; then
56
+ diff=$((az_count - src_count))
57
+ echo " ⚠ $diff Eintraege ohne Source-Verlinkung — Provenance-Disziplin §5 pruefen"
58
+ issues=$((issues + 1))
59
+ else
60
+ echo " ✓ alle Eintraege haben Source-Verlinkung"
61
+ fi
62
+
63
+ # 3. Verzeichnis-Vollstaendigkeit
64
+ echo "3/5 Verzeichnis-Vollstaendigkeit…"
65
+ required=("SKILL.md" "README.md" "LICENSE" "CHANGELOG.md" \
66
+ "references/audit-patterns.md" "references/dsgvo.md" "references/it-recht.md" \
67
+ "references/vertragsrecht.md" "references/checklisten.md" "references/branchenrecht.md" \
68
+ "references/bgh-urteile.md" "references/abmahn-templates.md" "references/aegis-integration.md" \
69
+ "references/international.md" "references/strafrecht-steuer.md" \
70
+ "references/templates/README.md" \
71
+ "references/gesetze/INDEX.md" \
72
+ "references/stack-patterns/INDEX.md")
73
+
74
+ missing=0
75
+ for f in "${required[@]}"; do
76
+ if [[ ! -f "$SKILL_DIR/$f" ]]; then
77
+ echo " ✗ fehlt: $f"
78
+ missing=$((missing + 1))
79
+ fi
80
+ done
81
+ if [[ "$missing" == "0" ]]; then
82
+ echo " ✓ alle ${#required[@]} Pflicht-Files vorhanden"
83
+ else
84
+ echo " ✗ $missing Pflicht-Files fehlen"
85
+ issues=$((issues + 1))
86
+ fi
87
+
88
+ # 4. SKILL.md Reference-Loading-Map → File-Vorhandensein
89
+ echo "4/5 Reference-Loading-Map konsistent…"
90
+ map_files=$(grep -oE 'references/[a-z_-]+\.md' "$SKILL_DIR/SKILL.md" 2>/dev/null | sort -u)
91
+ for f in $map_files; do
92
+ if [[ ! -f "$SKILL_DIR/$f" ]]; then
93
+ echo " ✗ SKILL.md verlinkt $f, aber Datei fehlt"
94
+ issues=$((issues + 1))
95
+ fi
96
+ done
97
+ echo " ✓ alle in SKILL.md referenzierten Files vorhanden"
98
+
99
+ # 5. Templates ohne Brand-Leak — re-uses the BRAND_PATTERN configured above
100
+ # in section 1. Templates must not contain any operator-specific codename.
101
+ echo "5/5 Templates anonymisiert…"
102
+ template_brand_hits=$( (grep -rEnli "$BRAND_PATTERN" \
103
+ "$SKILL_DIR/references/templates/" 2>/dev/null || true) | wc -l | tr -d ' ')
104
+ if [[ "$template_brand_hits" == "0" ]]; then
105
+ echo " ✓ alle Templates anonymisiert"
106
+ else
107
+ echo " ✗ Templates enthalten Brand-Refs (sollten anonym sein):"
108
+ grep -rEni "$BRAND_PATTERN" \
109
+ "$SKILL_DIR/references/templates/" 2>/dev/null | head -10 || true
110
+ issues=$((issues + 1))
111
+ fi
112
+
113
+ echo
114
+ if [[ "$issues" == "0" ]]; then
115
+ echo "✓ Health-Check passed — Skill ist konsistent."
116
+ exit 0
117
+ else
118
+ echo "✗ Health-Check failed — $issues Issues gefunden."
119
+ exit 1
120
+ fi
@@ -129,6 +129,91 @@ $$;
129
129
 
130
130
  **SECURITY DEFINER without `SET search_path` is a search-path-poisoning vulnerability** — the function inherits the caller's search_path and an attacker who can prepend their own schema can hijack the function.
131
131
 
132
+ ### 4a. SECURITY DEFINER RPC + `p_user_id` parameter — canonical authz guard
133
+
134
+ Pattern surfaced in production audits (CWE-863, IDOR via RPC): SECURITY DEFINER RPCs in the `public` schema accept a `p_user_id` parameter without verifying it equals `auth.uid()`. Every signed-in user can then call the RPC with any other user's id and act on their data:
135
+
136
+ - spend OTHER users' loyalty points (`purchase_item(other_uid, ...)`)
137
+ - award themselves arbitrary points (`award_points(my_uid, 999999)`)
138
+ - redeem rewards or finish duels on behalf of other users
139
+
140
+ These are **silent vulnerabilities** until Supabase ships a linter rule that surfaces them. Splinter rules `0028_anon_security_definer_function_executable` + `0029_authenticated_security_definer_function_executable` (added in early 2026) flag the privilege side, but they are argument-blind — a function can be linter-clean but still missing the internal `auth.uid()` check. Static migration audit catches the body-side gap at PR review.
141
+
142
+ **Canonical fix — install a single guard helper, then PERFORM it at the top of every RPC that takes a user-identity parameter:**
143
+
144
+ ```sql
145
+ -- One helper, owned by you, called everywhere
146
+ CREATE OR REPLACE FUNCTION public._aegis_authorize_user(p_user_id uuid)
147
+ RETURNS void
148
+ LANGUAGE plpgsql
149
+ SECURITY INVOKER
150
+ STABLE
151
+ SET search_path = ''
152
+ AS $$
153
+ BEGIN
154
+ IF (SELECT auth.role()) = 'service_role' THEN
155
+ RETURN; -- server-side admin / cron bypass
156
+ END IF;
157
+ IF (SELECT auth.uid()) IS NULL OR (SELECT auth.uid()) <> p_user_id THEN
158
+ RAISE EXCEPTION 'AEGIS-AUTHZ: caller % may not act on user %',
159
+ coalesce((SELECT auth.uid())::text, 'anon'), p_user_id
160
+ USING ERRCODE = '42501';
161
+ END IF;
162
+ END;
163
+ $$;
164
+
165
+ -- Every RPC that touches another user's data calls this on entry
166
+ CREATE FUNCTION public.purchase_arena_item(p_user_id uuid, p_item_key text)
167
+ RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER
168
+ SET search_path = public, pg_temp AS $$
169
+ BEGIN
170
+ PERFORM public._aegis_authorize_user(p_user_id); -- ← MANDATORY first line
171
+ -- ... actual logic
172
+ END $$;
173
+ ```
174
+
175
+ **Linter-clean grants — REVOKE from PUBLIC, not from anon:**
176
+ The default `EXECUTE` privilege on a SQL function is granted to `PUBLIC`, which transitively includes `anon`, `authenticated`, AND `service_role`. `REVOKE EXECUTE FROM anon` does **not** remove anon's access while the PUBLIC grant exists. To restrict to `authenticated` + `service_role`, you must:
177
+
178
+ ```sql
179
+ REVOKE ALL ON FUNCTION public.<name>(<args>) FROM PUBLIC, anon;
180
+ GRANT EXECUTE ON FUNCTION public.<name>(<args>) TO authenticated, service_role;
181
+ ```
182
+
183
+ **Bulk programmatic application** (idempotent — auto-discovers all guarded RPCs):
184
+
185
+ ```sql
186
+ DO $$
187
+ DECLARE r record;
188
+ BEGIN
189
+ FOR r IN
190
+ SELECT p.proname, pg_get_function_identity_arguments(p.oid) AS args
191
+ FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
192
+ WHERE n.nspname = 'public' AND p.prosecdef = true
193
+ AND p.prorettype <> 'trigger'::regtype
194
+ AND p.prosrc ~ '_aegis_authorize_user' -- only the guarded ones
195
+ LOOP
196
+ EXECUTE format('REVOKE ALL ON FUNCTION public.%I(%s) FROM PUBLIC, anon',
197
+ r.proname, r.args);
198
+ EXECUTE format('GRANT EXECUTE ON FUNCTION public.%I(%s) TO authenticated, service_role',
199
+ r.proname, r.args);
200
+ END LOOP;
201
+ END $$;
202
+ ```
203
+
204
+ **Decision tree for a SECURITY DEFINER function in `public`:**
205
+
206
+ | Function shape | Treatment |
207
+ |---|---|
208
+ | Returns `trigger` (called only by trigger system) | `REVOKE EXECUTE FROM PUBLIC, anon, authenticated`. Triggers run as table-owner regardless. |
209
+ | Cron / batch / admin-only (`cleanup_*`, `auto_unban_*`, `expire_*`) | `REVOKE FROM PUBLIC, anon, authenticated`. Only `service_role` may call. No internal guard needed. |
210
+ | User-callable RPC with `p_user_id` parameter | Inject `PERFORM _aegis_authorize_user(p_user_id);` at top. `REVOKE FROM PUBLIC, anon`; `GRANT TO authenticated, service_role`. |
211
+ | User-callable RPC with resource ID (`p_dog_id`, `p_post_id`) | Verify caller-ownership (or prefer `SECURITY INVOKER` and let RLS filter). |
212
+ | Read-only data accessor over RLS-protected tables | Switch to `SECURITY INVOKER`. RLS handles authz. |
213
+ | PostGIS / extension-owned C functions | Cannot revoke (extension owns them). Move PostGIS to `extensions` schema instead. |
214
+
215
+ **Why this surfaces in established projects without warning:** the Supabase database linter is rule-versioned. New rules ship without a code-change in your repo, and they retroactively flag patterns that were always exposures but were never explicitly checked. **Run `get_advisors` (or the SQL surrogates above) on every deploy**, not just at release.
216
+
132
217
  ### 5. Defensive testing — every policy needs a regression test
133
218
 
134
219
  ```sql
@@ -167,6 +252,31 @@ Order of operations:
167
252
 
168
253
  Run `aegis scan .` on your repo; fix everything `rls-bypass-checker` and `tenant-isolation-checker` flag before going to production.
169
254
 
255
+ ## Complementary external skill (mandatory)
256
+
257
+ This AEGIS skill covers the **security-remediation layer** —
258
+ scanner-finding mapping, incident-response, multi-tenant
259
+ isolation invariants. It does **not** cover RLS performance
260
+ optimization in depth, because that is the upstream Supabase
261
+ team's domain and is maintained as a separate skill.
262
+
263
+ When working on RLS at any depth, install the upstream Supabase
264
+ skill package once, globally:
265
+
266
+ ```bash
267
+ npx skills add supabase/agent-skills -g -y
268
+ ```
269
+
270
+ That ships
271
+ [`supabase-postgres-best-practices`](https://github.com/supabase/agent-skills/tree/main/skills/supabase-postgres-best-practices),
272
+ whose three `security-*` reference files complement this skill:
273
+
274
+ - `references/security-rls-basics.md` — the canonical RLS-enable + policy pattern as Supabase recommends it.
275
+ - `references/security-rls-performance.md` — the `(select auth.uid())` wrap that turns a per-row function call into a single-evaluation cached call (5–10x faster on large tables), security-definer helper functions for complex membership checks, and the discipline of indexing every column referenced inside an RLS policy.
276
+ - `references/security-privileges.md` — least-privilege role design and GRANT minimization, the layer beneath RLS.
277
+
278
+ When the AEGIS `rls-bypass-checker` flags a finding and you have a working policy fix, consult the upstream `security-rls-performance.md` next to ensure the fixed policy is also performant on production-sized tables. RLS that is correct but slow gets disabled by stressed engineers, which re-opens the security hole.
279
+
170
280
  ## See also
171
281
 
172
282
  - AEGIS scaffold's RLS bootstrap migration — `aegis new <project>` ships a `tenants` + `profiles` table + auto-profile-on-signup trigger pre-wired.
@@ -218,6 +218,32 @@ Run this on every CI run. Tenant-isolation regressions silently leak data; you n
218
218
  - `mass-assignment-checker` (CWE-915) — flags unvalidated body → `.insert()`.
219
219
  - `aegis-wizard/cli` scaffold — ships `secureApiRouteWithTenant`, the `tenants` + `profiles` schema with the auto-profile-on-signup trigger, and an exemplary API route demonstrating the composition pattern.
220
220
 
221
+ ## Complementary external skill (mandatory)
222
+
223
+ This skill covers **API-route-level tenant isolation**: the
224
+ `secureApiRouteWithTenant` primitive, JWT-sourced tenant
225
+ injection, request-input rejection, and AEGIS scanner-finding
226
+ remediation. It does not cover the broader Supabase development
227
+ surface (Auth setup, Edge Functions, Realtime, Storage,
228
+ migration workflow, MCP server integration) or Postgres
229
+ performance.
230
+
231
+ When designing a multi-tenant Supabase project, install the
232
+ upstream Supabase skill package once, globally:
233
+
234
+ ```bash
235
+ npx skills add supabase/agent-skills -g -y
236
+ ```
237
+
238
+ The two skills it ships are complementary to this one:
239
+
240
+ - [`supabase`](https://github.com/supabase/agent-skills/tree/main/skills/supabase) — the comprehensive Supabase development skill: the JWT vs `app_metadata` vs `user_metadata` security trap (critical for tenant-isolation policies), `WITH (security_invoker = true)` for views (RLS bypass otherwise), Storage upsert needing INSERT+SELECT+UPDATE (silent failures otherwise), CLI / migration / MCP workflow.
241
+ - [`supabase-postgres-best-practices`](https://github.com/supabase/agent-skills/tree/main/skills/supabase-postgres-best-practices) — Postgres performance reference: the `security-rls-performance.md` and `security-privileges.md` files complement this skill's tenant-filtering invariant with performance and least-privilege discipline.
242
+
243
+ The mandate is documented at the top of the AEGIS repository in
244
+ [`AGENTS.md`](../../../../../../AGENTS.md) and in the skills package
245
+ [`ATTRIBUTION.md`](../../../../ATTRIBUTION.md#required-external-skills-mandatory-complement-not-forked).
246
+
221
247
  ## See also
222
248
 
223
249
  - `defensive-rls-defense` skill — the RLS counterpart that complements API-route-level isolation.