@aegis-scan/skills 0.1.1 → 0.2.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 (32) hide show
  1. package/ATTRIBUTION.md +71 -20
  2. package/CHANGELOG.md +43 -0
  3. package/README.md +66 -18
  4. package/dist/commands/install.d.ts.map +1 -1
  5. package/dist/commands/install.js +17 -1
  6. package/dist/commands/install.js.map +1 -1
  7. package/package.json +3 -2
  8. package/sbom.cdx.json +1 -0
  9. package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +305 -0
  10. package/skills/compliance/aegis-native/brutaler-anwalt/references/abmahn-templates.md +306 -0
  11. package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +241 -0
  12. package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +277 -0
  13. package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +167 -0
  14. package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +285 -0
  15. package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +276 -0
  16. package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +238 -0
  17. package/skills/compliance/aegis-native/brutaler-anwalt/references/international.md +163 -0
  18. package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +267 -0
  19. package/skills/compliance/aegis-native/brutaler-anwalt/references/strafrecht-steuer.md +193 -0
  20. package/skills/compliance/aegis-native/brutaler-anwalt/references/vertragsrecht.md +243 -0
  21. package/skills/defensive/README.md +33 -4
  22. package/skills/defensive/aegis-native/rls-defense/SKILL.md +174 -0
  23. package/skills/defensive/aegis-native/ssrf-defense/SKILL.md +179 -0
  24. package/skills/defensive/aegis-native/tenant-isolation-defense/SKILL.md +225 -0
  25. package/skills/mitre-mapped/README.md +36 -8
  26. package/skills/mitre-mapped/aegis-native/mapping-overview/SKILL.md +129 -0
  27. package/skills/mitre-mapped/aegis-native/t1078-valid-accounts/SKILL.md +136 -0
  28. package/skills/mitre-mapped/aegis-native/t1190-exploit-public-app/SKILL.md +108 -0
  29. package/skills/ops/README.md +39 -4
  30. package/skills/ops/aegis-native/escalation-runbook/SKILL.md +147 -0
  31. package/skills/ops/aegis-native/suppress-correctly/SKILL.md +196 -0
  32. package/skills/ops/aegis-native/triage-finding/SKILL.md +144 -0
@@ -0,0 +1,243 @@
1
+ # Vertragsrecht & AGB — Referenz (Deutschland)
2
+
3
+ > Lade diese Datei bei: AGB-Prüfung, Softwareverträgen, SaaS-Verträgen, Kündigung, Gewährleistung, Haftungsbegrenzung, Verbraucherrecht, B2B-Verträgen, Mängeln, Schadensersatz.
4
+
5
+ ---
6
+
7
+ ## Primäre Rechtsquellen
8
+
9
+ | Gesetz | Volltext | Relevanz |
10
+ |--------|---------|---------|
11
+ | **BGB** (Bürgerliches Gesetzbuch) | https://www.gesetze-im-internet.de/bgb/ | Grundlage aller Schuldverhältnisse |
12
+ | **HGB** (Handelsgesetzbuch) | https://www.gesetze-im-internet.de/hgb/ | Kaufmännischer Geschäftsverkehr |
13
+ | **AGBG** (in BGB integriert) | BGB §§ 305-310 | AGB-Recht |
14
+ | **VerbrRRL** Umsetzung | BGB §§ 312 ff. | Verbrauchervertragsrecht, Widerrufsrecht |
15
+ | **Digitale-Inhalte-Richtlinie** | BGB §§ 327 ff. | Software, Apps, digitale Inhalte (seit 2022) |
16
+ | **PRIS** / Preisangabenverordnung | https://www.gesetze-im-internet.de/pangv/ | Preisangaben gegenüber Verbrauchern |
17
+ | **ProdHaftG** | https://www.gesetze-im-internet.de/prodhaftg/ | Produkthaftung (inkl. Software seit 2024) |
18
+
19
+ ---
20
+
21
+ ## AGB-Recht (BGB §§ 305-310)
22
+
23
+ ### Was sind AGB?
24
+ Vorformulierte Vertragsbedingungen, die für eine Vielzahl von Verträgen gestellt werden (§ 305 Abs. 1 BGB).
25
+ - Auch "Nutzungsbedingungen", "Terms of Service", "Allgemeine Geschäftsbedingungen", "Lizenzbedingungen" sind AGB
26
+ - Gilt auch für einmalig verwendete Klauseln, wenn erkennbar vorformuliert (bei B2C)
27
+
28
+ ### Einbeziehungsvoraussetzungen (§ 305 Abs. 2 BGB)
29
+ - Ausdrücklicher **Hinweis** auf AGB bei Vertragsschluss
30
+ - **Möglichkeit der Kenntnisnahme** (Link/Anhang reicht; physische Übergabe nicht zwingend)
31
+ - **Einverständnis** des Vertragspartners (aktives Anklicken empfohlen)
32
+
33
+ ### Wichtige Verbote
34
+
35
+ #### Klauselverbote ohne Wertungsmöglichkeit (§ 309 BGB) — immer unwirksam bei B2C
36
+ - Kurzfristige Preiserhöhungen (§ 309 Nr. 1)
37
+ - Rücktrittsvorbehalte ohne Grund (§ 309 Nr. 3)
38
+ - Abtretungsverbote (§ 309 Nr. 13)
39
+ - Haftungsausschluss für Körperschäden (§ 309 Nr. 7a)
40
+ - Haftungsausschluss für grobe Fahrlässigkeit (§ 309 Nr. 7b)
41
+
42
+ #### Klauselverbote mit Wertungsmöglichkeit (§ 308 BGB)
43
+ - Unangemessen lange Lieferfristen (§ 308 Nr. 1)
44
+ - Unzumutbar lange Annahmeverweigerungsfristen (§ 308 Nr. 2)
45
+ - Automatische Vertragsverlängerung > 1 Jahr (§ 308 Nr. 3) — **bei B2C!**
46
+ - Vorbehalt wesentlicher Leistungsänderungen (§ 308 Nr. 4)
47
+
48
+ #### Generalklausel (§ 307 BGB) — gilt auch B2B
49
+ - Klauseln, die **unangemessen benachteiligen**
50
+ - Verstoß gegen wesentliche Grundgedanken der gesetzlichen Regelung
51
+ - Einschränkung wesentlicher Rechte/Pflichten, die Vertragszweck gefährdet
52
+
53
+ ### B2B vs. B2C — Wichtige Unterschiede
54
+ | Aspekt | B2C (§§ 307-309 BGB) | B2B (§ 307 BGB) |
55
+ |--------|---------------------|----------------|
56
+ | Prüfungsmaßstab | Streng | Milder |
57
+ | § 308, 309 Verbote | Direkt anwendbar | Nur Indizwirkung |
58
+ | Haftungsausschluss grobe Fahrlässigkeit | Unwirksam | Eingeschränkt möglich |
59
+ | Gewährleistungsausschluss | Sehr begrenzt | Weitgehend möglich |
60
+ | Verkürzung Verjährung | Max. 1 Jahr | Auf 1 Jahr möglich |
61
+
62
+ ---
63
+
64
+ ## Vertragstypen im IT-Bereich
65
+
66
+ ### Softwarekauf — Kaufrecht (BGB §§ 433 ff.)
67
+ **Wann:** Dauerhafte Überlassung von Standardsoftware (Download, physisch)
68
+
69
+ **Mängelrechte (§ 437 BGB):**
70
+ 1. Nacherfüllung (Reparatur oder Ersatz) — Vorrang
71
+ 2. Rücktritt oder Minderung (nach gescheiterter Nacherfüllung)
72
+ 3. Schadensersatz oder Aufwendungsersatz
73
+
74
+ **Verjährung:** 2 Jahre ab Lieferung (§ 438 BGB); bei arglistigem Verschweigen: 3 Jahre
75
+
76
+ **Digitale Inhalte (seit 2022, §§ 327 ff. BGB):**
77
+ - Gilt für Software, Apps, eBooks, Streaming
78
+ - Aktualisierungspflicht: Anbieter muss Updates bereitstellen, die für Vertragsgemäßheit nötig sind
79
+ - Gilt auch für "kostenlose" Dienste, bei denen Daten die Gegenleistung sind
80
+
81
+ ### SaaS / Cloud — Mietrecht (BGB §§ 535 ff.)
82
+ **Wann:** Zeitlich begrenzte Nutzung (Abo-Modell, Pay-per-Use)
83
+
84
+ **Pflichten des Anbieters:**
85
+ - Taugliche Überlassung über gesamte Mietzeit (§ 535 Abs. 1 BGB)
86
+ - Mängelbeseitigung ohne Ankündigungsfrist bei erheblichem Mangel
87
+
88
+ **Mängelrechte des Nutzers:**
89
+ - Mietminderung (§ 536 BGB) — automatisch, keine Anzeige nötig
90
+ - Kündigung bei erheblichem Mangel (§ 543 BGB)
91
+ - Schadensersatz (§ 536a BGB) — bei anfänglichem Mangel ohne Verschulden!
92
+
93
+ **Kündigung:**
94
+ - Ordentlich: Vertragliche Regelungen; subsidiär §§ 580a, 565 BGB
95
+ - Außerordentlich: § 543 BGB (wichtiger Grund)
96
+
97
+ **SLA-Klauseln:** Downtime-Regelungen, Wartungsfenster, Response Times — AGB-rechtlich prüfen!
98
+
99
+ ### Individualentwicklung — Werkvertragsrecht (BGB §§ 631 ff.)
100
+ **Wann:** Erstellung maßgeschneiderter Software
101
+
102
+ **Abnahme (§ 640 BGB):**
103
+ - Pflicht zur Abnahme bei mangelfreier Leistung
104
+ - Keine Abnahme bei wesentlichen Mängeln
105
+ - Fiktive Abnahme nach Fristablauf möglich (§ 640 Abs. 2 BGB)
106
+ - **Tipp:** Abnahmeprotokoll schriftlich festhalten
107
+
108
+ **Nach Abnahme:**
109
+ - Gefahr geht auf Besteller über
110
+ - Verjährung beginnt zu laufen
111
+
112
+ **Mängelrechte nach Abnahme (§ 634 BGB):**
113
+ 1. Nacherfüllung (§ 635) — Vorrang, 2 Versuche angemessen
114
+ 2. Selbstvornahme + Kostenersatz (§ 637) — nach gescheiterter Nacherfüllung
115
+ 3. Rücktritt oder Minderung (§§ 636, 638) — nach gescheiterter Nacherfüllung
116
+ 4. Schadensersatz (§ 636 i.V.m. §§ 280 ff.)
117
+
118
+ **Verjährung:** 2 Jahre ab Abnahme (§ 634a Abs. 1 Nr. 1 BGB)
119
+
120
+ ### Pflege- und Wartungsvertrag
121
+ - Meist Dienstvertrag (kein Erfolg geschuldet) oder Werkvertrag (konkrete Updates)
122
+ - **Klarheit schaffen:** Was genau ist Pflegeinhalt? Reaktionszeiten? SLAs?
123
+ - Kündigung: Dienstvertrag § 621 BGB (fristgerecht); Werkvertrag § 649 BGB (jederzeit, aber Vergütung fällig)
124
+
125
+ ---
126
+
127
+ ## Haftungsbegrenzungen — Was ist möglich?
128
+
129
+ ### Gesetzliche Grenzen (unveränderlich)
130
+ - **Kein Ausschluss** bei Vorsatz (§ 276 Abs. 3 BGB)
131
+ - **Kein Ausschluss** bei grober Fahrlässigkeit und Körper-/Gesundheitsschäden (§ 309 Nr. 7 BGB bei B2C)
132
+ - **Produkthaftung** (ProdHaftG) ist zwingend — kein Ausschluss möglich
133
+ - **DSGVO-Haftung** (Art. 82) kann nicht durch AGB ausgeschlossen werden
134
+
135
+ ### Was geht (B2B)?
136
+ - Haftungsausschluss für einfache Fahrlässigkeit (außer Kardinalpflichten)
137
+ - Haftungshöchstbeträge (z.B. auf Vertragswert begrenzt)
138
+ - Ausschluss mittelbarer Schäden / entgangener Gewinn (mit Einschränkungen)
139
+ - Verkürzung Verjährung auf 1 Jahr (nicht bei Arglist)
140
+
141
+ ### Was geht (B2C)?
142
+ - Sehr begrenzt: Ausschluss nur bei leichter Fahrlässigkeit + Nicht-Kardinalpflicht + kein Körperschaden
143
+ - Haftungshöchstbeträge: Nur wenn angemessen
144
+ - Praktisch: Fast keine sinnvolle Haftungsbegrenzung gegenüber Verbrauchern möglich
145
+
146
+ ---
147
+
148
+ ## Gewährleistung vs. Garantie
149
+
150
+ | Begriff | Basis | Inhalt |
151
+ |---------|-------|--------|
152
+ | **Gewährleistung** | Gesetzlich (BGB) | Pflicht, Mängel zu beseitigen — unverzichtbar bei B2C |
153
+ | **Garantie** | Freiwillig (vertraglich) | Zusätzliche Versprechen (24-Monate-Garantie etc.) |
154
+
155
+ **Verjährungsfristen Gewährleistung:**
156
+ - B2C Kauf: 2 Jahre (§ 438 Abs. 1 Nr. 3 BGB) — nicht verkürzbar
157
+ - B2B Kauf: 2 Jahre — auf 1 Jahr verkürzbar per AGB
158
+ - Werk: 2 Jahre ab Abnahme — auf 1 Jahr verkürzbar per AGB (B2B)
159
+ - Arglist: 3 Jahre (kenntnisabhängig, § 199 BGB)
160
+
161
+ ---
162
+
163
+ ## Widerrufsrecht (B2C, §§ 312 ff. BGB)
164
+
165
+ ### Wann gilt es?
166
+ - Fernabsatzverträge (Online, Telefon) mit Verbrauchern
167
+ - **14 Tage** ab Vertragsschluss oder Erhalt der Ware
168
+
169
+ ### Ausnahmen (§ 312g Abs. 2 BGB)
170
+ - Digitale Inhalte (Software, Downloads): Kein Widerruf, wenn Ausführung mit Zustimmung begonnen
171
+ - Maßgeschneiderte Waren/Leistungen
172
+ - Versiegelte Waren nach Öffnung
173
+
174
+ ### Widerrufsbelehrung
175
+ - Muss klar und deutlich vor Vertragsschluss bereitgestellt werden
176
+ - Fehler → Widerrufsfrist verlängert sich auf 12 Monate + 14 Tage (§ 356 Abs. 3 BGB)
177
+ - Muster: Anlage 1 zu Art. 246a § 1 Abs. 2 S. 2 EGBGB
178
+
179
+ ---
180
+
181
+ ## Preisangaben (PAngV / § 5a UWG)
182
+
183
+ ### Pflichten gegenüber Verbrauchern
184
+ - **Endpreis** inkl. MwSt. und sonstiger Preisbestandteile
185
+ - **Grundpreis** bei Waren nach Gewicht/Volumen/Länge/Fläche
186
+ - Preisangabe vor Vertragsschluss, nicht erst im Checkout
187
+ - Fake-Rabatte verboten: Rabatt nur auf tatsächlichen Vorpreis
188
+
189
+ ### Besonderheiten SaaS / Abonnements
190
+ - Gesamtkosten der Mindestlaufzeit angeben
191
+ - Automatische Verlängerung transparent machen
192
+ - Preiserhöhungen: Rechtzeitige Information + Kündigungsrecht
193
+
194
+ ---
195
+
196
+ ## Vertragliche Besonderheiten bei Fremdentwicklern / Freelancern
197
+
198
+ ### Scheinselbstständigkeit (§ 7 SGB IV)
199
+ - Auftraggeber trägt Risiko bei Scheinselbstständigkeit (Nachzahlung Sozialversicherung!)
200
+ - Prüfkriterien: Weisungsgebundenheit, Integration in Organisation, eigenes Unternehmerrisiko
201
+ - **Statusfeststellungsverfahren** beim Rentenversicherungsträger möglich
202
+
203
+ ### IP-Übertragung / Nutzungsrechte
204
+ - Ohne Regelung: Entwickler behält alle Rechte!
205
+ - Im Vertrag klarstellen: Umfang der Nutzungsrechte, exklusiv vs. nicht-exklusiv
206
+ - Quellcode-Übergabe explizit vereinbaren
207
+ - Nutzungsrechte für Dritte (z.B. Kunden des Auftraggebers) separat einräumen lassen
208
+
209
+ ### Vertraulichkeit / NDA
210
+ - Gegenseitiges NDA vor Projektbeginn empfehlenswert
211
+ - Vertragsstrafe für Verstöße vereinbaren
212
+ - Ausnahmen: öffentlich bekannte Informationen, gesetzliche Offenlegungspflichten
213
+
214
+ ---
215
+
216
+ ## Checkliste: Wichtige Klauseln im IT-Vertrag
217
+
218
+ ### Essentialia (Pflichtinhalt)
219
+ - [ ] Leistungsgegenstand präzise beschrieben (Lastenheft / Pflichtenheft)
220
+ - [ ] Vergütung und Zahlungsbedingungen
221
+ - [ ] Laufzeit und Kündigung
222
+ - [ ] Abnahme- und Lieferkonditionen
223
+
224
+ ### Empfohlene Klauseln
225
+ - [ ] Gewährleistung und Haftung (unter Beachtung AGB-Recht)
226
+ - [ ] Datenschutz und AVV-Verweis
227
+ - [ ] Vertraulichkeit / NDA
228
+ - [ ] Nutzungsrechte / IP-Übertragung
229
+ - [ ] Eskalations- und Änderungsmanagement (Change Request Prozess)
230
+ - [ ] SLA / Verfügbarkeitsgarantien
231
+ - [ ] Subunternehmer-Regelung
232
+ - [ ] Audit- und Kontrollrechte
233
+ - [ ] Exportkontrolle (bei internationalen Projekten)
234
+ - [ ] Gerichtsstand und anwendbares Recht (bei internationalen Verträgen)
235
+ - [ ] Schriftformklausel / Textformklausel
236
+
237
+ ### Häufige Fallen
238
+ - ❌ Zu weite Haftungsfreizeichnungen (unwirksam nach AGB-Recht)
239
+ - ❌ Unklare Abnahmeregelungen (Abnahme wird nie formal erklärt)
240
+ - ❌ Fehlende IP-Klausel (Entwickler behält Rechte)
241
+ - ❌ Automatische Verlängerung mit sehr langer Kündigungsfrist (§ 308 Nr. 3 BGB bei B2C)
242
+ - ❌ Preiserhöhungsklausel ohne Kündigungsrecht (unwirksam bei B2C)
243
+ - ❌ Kein Change-Request-Verfahren (führt zu Streit über Mehraufwand)
@@ -1,8 +1,37 @@
1
- # Defensive Skills
1
+ # Defensive Skills — `defensive/`
2
2
 
3
- Reserved for AEGIS-native defensive skill modules in `skills-v0.2+`.
4
- Mirrors wizard-cli security patterns into SKILL.md format for agent
5
- consumption. Content lands in a future release.
3
+ Defensive-security methodology skills for AI coding agents (Claude Code,
4
+ Cursor, etc.). Each skill is a self-contained `SKILL.md` with YAML
5
+ frontmatter that the agent auto-loads when its trigger-keywords match a
6
+ user prompt.
7
+
8
+ ## Sources
9
+
10
+ | Source dir | License | Skills |
11
+ |---|---|---|
12
+ | `aegis-native/` | MIT (AEGIS-original) | 3 |
13
+
14
+ ## AEGIS-native skills
15
+
16
+ These skills are AEGIS-original content, mirroring patterns from
17
+ `@aegis-wizard/cli`'s pattern library and remediation guidance for
18
+ `@aegis-scan/cli` scanner findings.
19
+
20
+ | Skill | Addresses scanner findings |
21
+ |---|---|
22
+ | `rls-defense` | `rls-bypass-checker` (CWE-863), `template-sql-checker` (CWE-89) |
23
+ | `tenant-isolation-defense` | `tenant-isolation-checker` (CWE-639), `mass-assignment-checker` (CWE-915) |
24
+ | `ssrf-defense` | `ssrf-checker` (CWE-918), `taint-analyzer` (CWE-918) |
25
+
26
+ License: MIT. See top-level [`ATTRIBUTION.md`](../../ATTRIBUTION.md) for
27
+ attribution chain.
28
+
29
+ ## Roadmap
30
+
31
+ Future expansions in this category may include:
32
+
33
+ - Cherry-picks from external CC BY-SA / Apache-2.0 / MIT defensive-skill libraries (per the maintainer's source-evaluation cycle).
34
+ - Additional AEGIS-native skills covering the remaining defensive scanner family (csrf-defense, header-defense, prompt-injection-defense, secret-management-defense, supply-chain-defense, etc.).
6
35
 
7
36
  The broader skill-ecosystem roadmap is maintained in the repository's
8
37
  internal planning tree; ask the maintainer for access if you are
@@ -0,0 +1,174 @@
1
+ <!-- aegis-local: AEGIS-native skill, MIT-licensed; mirrors @aegis-wizard/cli RLS-defense pattern + addresses AEGIS scanner findings: rls-bypass-checker (CWE-863), tenant-isolation-checker (CWE-639). -->
2
+
3
+ ---
4
+ name: defensive-rls-defense
5
+ description: "Supabase Row-Level Security (RLS) hardening methodology. Covers RLS policy design, auth.uid() vs auth.jwt(), service-role-key safety, .rpc() function security, AEGIS rls-bypass-checker remediation, multi-tenant isolation patterns, defensive defaults, regression test patterns, and incident-response when RLS is bypassed. Use when designing or auditing Supabase schemas, fixing rls-bypass-checker findings, hardening multi-tenant SaaS applications, or responding to suspected cross-tenant data leakage."
6
+ ---
7
+
8
+ # RLS Defense — Supabase Row-Level Security Methodology
9
+
10
+ ## When to use this skill
11
+
12
+ - Designing a new Supabase project — set up RLS correctly from commit 0.
13
+ - Reviewing an existing schema — verify RLS policies actually enforce isolation.
14
+ - Fixing AEGIS `rls-bypass-checker` (CWE-863) or `tenant-isolation-checker` (CWE-639) findings.
15
+ - Responding to suspected cross-tenant data leakage incidents.
16
+ - Hardening before a security audit (SOC 2 / ISO 27001 / PCI-DSS).
17
+
18
+ ## The core invariant
19
+
20
+ **Every table that holds user-scoped or tenant-scoped data MUST have RLS enabled AND at least one policy that bounds visibility to the requesting user/tenant.** Tables without RLS are a critical exposure; tables with RLS but no policies are equally critical (RLS-enabled-without-policy denies everything but is easy to reverse with a wildcard policy that opens the door).
21
+
22
+ ## Defensive design checklist
23
+
24
+ ### 1. RLS-enabled-by-default discipline
25
+
26
+ ```sql
27
+ -- Enable RLS on every table that holds user/tenant data
28
+ ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
29
+ ALTER TABLE public.tenants ENABLE ROW LEVEL SECURITY;
30
+ ALTER TABLE public.documents ENABLE ROW LEVEL SECURITY;
31
+
32
+ -- Verify after every migration
33
+ SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
34
+ -- Every row should show rowsecurity = true (except for purely-public reference tables)
35
+ ```
36
+
37
+ ### 2. Policy patterns that actually isolate
38
+
39
+ **Owner-scoped (user owns rows):**
40
+
41
+ ```sql
42
+ CREATE POLICY "Users see only their own rows"
43
+ ON public.documents FOR SELECT
44
+ USING (auth.uid() = user_id);
45
+
46
+ CREATE POLICY "Users insert only with their own user_id"
47
+ ON public.documents FOR INSERT
48
+ WITH CHECK (auth.uid() = user_id);
49
+
50
+ CREATE POLICY "Users update only their own rows"
51
+ ON public.documents FOR UPDATE
52
+ USING (auth.uid() = user_id)
53
+ WITH CHECK (auth.uid() = user_id);
54
+
55
+ CREATE POLICY "Users delete only their own rows"
56
+ ON public.documents FOR DELETE
57
+ USING (auth.uid() = user_id);
58
+ ```
59
+
60
+ **Tenant-scoped (multi-tenant isolation):**
61
+
62
+ ```sql
63
+ -- Pattern: tenant_id flows through profiles → all tables
64
+ CREATE POLICY "Tenant-scoped read"
65
+ ON public.invoices FOR SELECT
66
+ USING (
67
+ tenant_id IN (
68
+ SELECT tenant_id FROM public.profiles
69
+ WHERE profiles.id = auth.uid()
70
+ )
71
+ );
72
+
73
+ -- Same shape for INSERT/UPDATE/DELETE with WITH CHECK on tenant_id.
74
+ ```
75
+
76
+ ### 3. Anti-patterns that break isolation
77
+
78
+ **Avoid `auth.jwt() ->> 'role'` for authorization decisions** — JWTs are operator-controllable and the token's claim can be spoofed if your `service_role` ever reaches client-side code.
79
+
80
+ **Avoid `service_role` keys in API routes that handle user input** — `service_role` bypasses RLS entirely. Every API route that uses `service_role` needs hand-rolled authorization to replace what RLS would have enforced.
81
+
82
+ **Avoid `.rpc()` with template-literal function names**:
83
+
84
+ ```typescript
85
+ // BAD: function name is interpolated, attacker can rename target function
86
+ await supabase.rpc(`get_${userInput}`, params)
87
+
88
+ // GOOD: function name is a literal
89
+ await supabase.rpc('get_user_documents', { user_id: validatedId })
90
+ ```
91
+
92
+ The `template-sql-checker` and `rls-bypass-checker` flag both shapes; this skill is the remediation methodology.
93
+
94
+ ### 4. RPC function security
95
+
96
+ PostgreSQL functions can run with `SECURITY DEFINER` (run as definer's role, often superuser) or `SECURITY INVOKER` (run as caller's role, default).
97
+
98
+ ```sql
99
+ -- DEFAULT — function runs as caller, RLS applies
100
+ CREATE FUNCTION public.get_user_docs()
101
+ RETURNS SETOF documents
102
+ LANGUAGE sql
103
+ SECURITY INVOKER -- explicit, even if default
104
+ AS $$
105
+ SELECT * FROM documents WHERE user_id = auth.uid();
106
+ $$;
107
+
108
+ -- SECURITY DEFINER ONLY when you need to break RLS for a specific elevated operation
109
+ -- AND every parameter is pre-validated
110
+ CREATE FUNCTION public.admin_audit_logs(target_user uuid)
111
+ RETURNS SETOF audit_log
112
+ LANGUAGE plpgsql
113
+ SECURITY DEFINER
114
+ SET search_path = public -- prevent search-path-poisoning
115
+ AS $$
116
+ BEGIN
117
+ -- Hand-rolled authorization check because RLS is bypassed
118
+ IF NOT EXISTS (
119
+ SELECT 1 FROM profiles
120
+ WHERE id = auth.uid() AND role = 'admin'
121
+ ) THEN
122
+ RAISE EXCEPTION 'unauthorized';
123
+ END IF;
124
+
125
+ RETURN QUERY SELECT * FROM audit_log WHERE user_id = target_user;
126
+ END;
127
+ $$;
128
+ ```
129
+
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
+
132
+ ### 5. Defensive testing — every policy needs a regression test
133
+
134
+ ```sql
135
+ -- Test as user A
136
+ SET LOCAL ROLE authenticated;
137
+ SET LOCAL request.jwt.claim.sub = 'user-a-uuid';
138
+
139
+ SELECT count(*) FROM documents; -- should equal A's row count, not all rows
140
+
141
+ SET LOCAL request.jwt.claim.sub = 'user-b-uuid';
142
+ SELECT count(*) FROM documents; -- should equal B's row count, NOT A's
143
+ ```
144
+
145
+ Wire this into your test suite. AEGIS doesn't run live SQL tests, but `tenant-isolation-checker` and `rls-bypass-checker` flag the patterns at code-review time.
146
+
147
+ ## Incident response — RLS bypassed
148
+
149
+ Order of operations:
150
+
151
+ 1. **Disclose internally** — RLS bypass = potential data breach; engage legal + DPO immediately.
152
+ 2. **Stop the bleeding** — disable the affected route or endpoint at the gateway level (Vercel / Cloudflare / load balancer) BEFORE patching code.
153
+ 3. **Audit log forensics** — Supabase logs every RLS-context query; pull the affected window's logs to bound the exposure.
154
+ 4. **Determine reach** — for each suspect query, identify the rows visible to each user-context vs the rows the user should have seen.
155
+ 5. **Patch and re-deploy** — fix the policy, re-deploy, verify with regression tests.
156
+ 6. **Notify affected users** — per GDPR Art. 33 within 72 hours of becoming aware.
157
+
158
+ ## How AEGIS scanners help
159
+
160
+ | Scanner | What it catches |
161
+ |---|---|
162
+ | `rls-bypass-checker` (CWE-863) | `service_role` usage in API routes, `.rpc()` template-injection patterns |
163
+ | `tenant-isolation-checker` (CWE-639) | Supabase queries missing `tenant_id` filter |
164
+ | `template-sql-checker` (CWE-89) | Template-literal SQL injection in `.rpc()` / `.execute()` / `.query()` / `.$queryRawUnsafe()` |
165
+ | `mass-assignment-checker` (CWE-915) | Unvalidated `request.json()` flowing into `.insert()` |
166
+ | `auth-enforcer` (CWE-285, 306) | API routes without auth guards |
167
+
168
+ Run `aegis scan .` on your repo; fix everything `rls-bypass-checker` and `tenant-isolation-checker` flag before going to production.
169
+
170
+ ## See also
171
+
172
+ - AEGIS scaffold's RLS bootstrap migration — `aegis new <project>` ships a `tenants` + `profiles` table + auto-profile-on-signup trigger pre-wired.
173
+ - AEGIS patterns library — `docs/patterns/index.md` documents the multi-tenant Supabase pattern catalog.
174
+ - Upstream Supabase docs — https://supabase.com/docs/guides/auth/row-level-security
@@ -0,0 +1,179 @@
1
+ <!-- aegis-local: AEGIS-native skill, MIT-licensed; mirrors @aegis-wizard/cli ssrf-defense pattern + addresses AEGIS scanner finding: ssrf-checker (CWE-918). -->
2
+
3
+ ---
4
+ name: defensive-ssrf
5
+ description: "Server-Side Request Forgery (SSRF) defense methodology. Covers RFC 1918 / link-local block-rules, allowlist-vs-denylist trade-offs, DNS rebinding defense, IPv6 considerations, cloud metadata-endpoint protection (AWS / GCP / Azure), proxy/redirect handling, AEGIS ssrf-checker remediation, and the SSRF-safe-fetch primitive. Use when designing fetch-from-user-input flows, fixing AEGIS ssrf-checker findings, or hardening SSRF-prone endpoints (image proxies, webhook receivers, OAuth callbacks)."
6
+ ---
7
+
8
+ # SSRF Defense — Server-Side Request Forgery Methodology
9
+
10
+ ## When to use this skill
11
+
12
+ - Building any feature where the server fetches a URL based on user input (image proxy, link preview, webhook delivery, OAuth callback, profile-picture import, document-rendering service).
13
+ - Fixing AEGIS `ssrf-checker` (CWE-918) findings.
14
+ - Hardening before a security audit, especially in cloud-deployed apps where metadata endpoints (`169.254.169.254`) are reachable.
15
+
16
+ ## The core invariant
17
+
18
+ **Server-initiated HTTP requests where the URL is user-controlled MUST validate that the resolved IP is in an allowed set BEFORE issuing the request, AND the validation must survive DNS rebinding.**
19
+
20
+ The "MUST survive DNS rebinding" is what kills naive defenses. An attacker controls a DNS server that returns a public IP on first lookup and a private IP on second lookup; if your code resolves the URL once for validation and again for the fetch, you lose.
21
+
22
+ ## The secure primitive
23
+
24
+ ```typescript
25
+ // lib/security/safeFetch.ts (AEGIS scaffold ships this)
26
+
27
+ import { lookup } from 'node:dns/promises';
28
+ import { isIP } from 'node:net';
29
+
30
+ /**
31
+ * SSRF-safe fetch — validates the resolved IP before issuing the request,
32
+ * and pins the resolution to defeat DNS rebinding.
33
+ */
34
+ export async function safeFetch(url: string, init?: RequestInit): Promise<Response> {
35
+ const parsed = new URL(url);
36
+
37
+ // Reject non-HTTP(S) schemes — file://, gopher://, dict://, etc.
38
+ if (!['http:', 'https:'].includes(parsed.protocol)) {
39
+ throw new Error(`SSRF: protocol ${parsed.protocol} not allowed`);
40
+ }
41
+
42
+ // Reject if hostname is already an IP literal in a forbidden range
43
+ if (isIP(parsed.hostname)) {
44
+ if (isForbiddenIP(parsed.hostname)) {
45
+ throw new Error(`SSRF: IP ${parsed.hostname} not allowed`);
46
+ }
47
+ } else {
48
+ // Resolve to an IP and verify
49
+ const { address } = await lookup(parsed.hostname);
50
+ if (isForbiddenIP(address)) {
51
+ throw new Error(`SSRF: ${parsed.hostname} → ${address} not allowed`);
52
+ }
53
+ // Defeat DNS rebinding — pin the resolved IP and use it for the fetch
54
+ const pinnedURL = parsed.protocol + '//' + address + parsed.pathname + parsed.search;
55
+ return fetch(pinnedURL, {
56
+ ...init,
57
+ headers: {
58
+ ...init?.headers,
59
+ Host: parsed.hostname, // preserve original hostname for SNI / Host-header routing
60
+ },
61
+ });
62
+ }
63
+
64
+ return fetch(url, init);
65
+ }
66
+
67
+ function isForbiddenIP(ip: string): boolean {
68
+ // Loopback
69
+ if (ip.startsWith('127.') || ip === '::1') return true;
70
+ // Private RFC 1918
71
+ if (ip.startsWith('10.')) return true;
72
+ if (/^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(ip)) return true;
73
+ if (ip.startsWith('192.168.')) return true;
74
+ // Link-local
75
+ if (ip.startsWith('169.254.')) return true;
76
+ if (ip.toLowerCase().startsWith('fe80:')) return true;
77
+ // Unique local IPv6 (fc00::/7)
78
+ if (/^f[cd]/i.test(ip)) return true;
79
+ // Cloud metadata
80
+ if (ip === '169.254.169.254') return true; // AWS / GCP / Azure / DO
81
+ if (ip === '169.254.170.2') return true; // ECS task metadata
82
+ // Carrier-grade NAT (RFC 6598)
83
+ if (/^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\./.test(ip)) return true;
84
+ return false;
85
+ }
86
+ ```
87
+
88
+ ## Why "just block 169.254.0.0/16" is not enough
89
+
90
+ Old advice: block 127.0.0.0/8 and 169.254.0.0/16. Modern requirement: also block:
91
+
92
+ - All RFC 1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) — internal services.
93
+ - IPv6 loopback (`::1`) and link-local (`fe80::/10`) and unique-local (`fc00::/7`).
94
+ - Carrier-grade NAT (100.64.0.0/10, RFC 6598) — your cloud may NAT here.
95
+ - The cloud-specific metadata IPs your provider exposes.
96
+ - Any "alias to localhost" hostnames your provider provides (e.g., `localhost`, `0.0.0.0`).
97
+
98
+ AEGIS's `ssrf-checker` and the scaffold's `safeFetch` cover all of these.
99
+
100
+ ## Anti-patterns
101
+
102
+ ### Anti-pattern 1 — naive allowlist on hostname before resolution
103
+
104
+ ```typescript
105
+ // BROKEN — bypassed by attacker-controlled DNS
106
+ const ALLOWED = ['api.partner.com'];
107
+ if (!ALLOWED.some(h => url.includes(h))) throw new Error('not allowed');
108
+ await fetch(url); // attacker registers `api.partner.com.attacker.com` — passes the .includes() check
109
+ ```
110
+
111
+ ### Anti-pattern 2 — validate-then-fetch (TOCTOU)
112
+
113
+ ```typescript
114
+ // BROKEN — DNS rebinding gap between validate and fetch
115
+ const { address } = await lookup(new URL(url).hostname);
116
+ if (isForbiddenIP(address)) throw new Error('blocked');
117
+ await fetch(url); // second resolution may now return a private IP
118
+ ```
119
+
120
+ Always **pin the resolved IP** for the actual fetch (see `safeFetch` above).
121
+
122
+ ### Anti-pattern 3 — trusting `fetch` to follow redirects safely
123
+
124
+ `fetch` follows up to 20 redirects by default. An attacker-controlled allowed URL can redirect to a private IP. Mitigate:
125
+
126
+ ```typescript
127
+ await safeFetch(url, { redirect: 'manual' });
128
+ ```
129
+
130
+ Then if the response is 3xx, re-validate the `Location` header through `safeFetch` before following.
131
+
132
+ ### Anti-pattern 4 — `encodeURIComponent` as SSRF defense
133
+
134
+ `encodeURIComponent` blocks XSS and SSRF-via-path-traversal (`../`), but it does NOT block SSRF-via-host. A URL like `http://169.254.169.254/latest/meta-data/` survives `encodeURIComponent` of the path component because the host part isn't encoded. The `ssrf-checker` per-CWE sanitizer-awareness logic catches this — `encodeURIComponent` is recognized as an XSS sanitizer but NOT as an SSRF sanitizer.
135
+
136
+ ## Cloud-metadata-endpoint protection
137
+
138
+ AWS, GCP, Azure, and DigitalOcean all expose internal metadata at `http://169.254.169.254/`. SSRF-to-metadata is the most common cloud breach pattern of the last decade.
139
+
140
+ AWS specifically provides IMDSv2 which adds a token-handshake — enable IMDSv2 on every instance:
141
+
142
+ ```bash
143
+ # AWS — enforce IMDSv2 (token-required) at instance level
144
+ aws ec2 modify-instance-metadata-options \
145
+ --instance-id <id> \
146
+ --http-tokens required \
147
+ --http-put-response-hop-limit 1
148
+ ```
149
+
150
+ But IMDSv2 is defense-in-depth; the primary defense is still application-level SSRF protection.
151
+
152
+ ## Webhook receivers — special case
153
+
154
+ Webhooks are RECEIVED rather than initiated, so SSRF doesn't directly apply. But the pattern of "process this URL someone gave us" often does — for example, a webhook may include a callback URL that your server then fetches. Apply the same `safeFetch` discipline.
155
+
156
+ For OAuth callbacks: the callback URL is operator-configured, not request-controlled, so SSRF doesn't apply. But verify the redirect_uri matches the registered URL exactly (not `startsWith`-style).
157
+
158
+ ## How AEGIS scanners help
159
+
160
+ | Scanner | What it catches |
161
+ |---|---|
162
+ | `ssrf-checker` (CWE-918) | `fetch(userInput)` patterns; recognizes `safeFetch`, `parseInt`, RFC 1918 / link-local literals, regex-guarded URL filters as sanitizers per per-CWE awareness rules |
163
+ | `taint-analyzer` (CWE-918) | Cross-file taint from request input → `fetch` sink |
164
+ | `open-redirect-checker` (CWE-601) | Sibling pattern — `redirect(userInput)` |
165
+ | `header-checker` (CWE-693) | CSP includes `connect-src` allowlist that limits client-side fetch destinations |
166
+
167
+ ## Incident response — SSRF exploited
168
+
169
+ 1. **Disclose internally** — immediately if the attacker reached the cloud metadata endpoint (potential credential theft).
170
+ 2. **Rotate cloud credentials** — assume any IAM credentials reachable via metadata are compromised.
171
+ 3. **Audit logs** — pull all outbound fetches from the affected service in the relevant window.
172
+ 4. **Patch and re-deploy** — replace the unsafe `fetch` with `safeFetch`.
173
+ 5. **Audit similar code paths** — SSRF tends to come in clusters; one finding usually has siblings.
174
+
175
+ ## See also
176
+
177
+ - AEGIS patterns library — `docs/patterns/index.md` § "Hardened middleware".
178
+ - `aegis-wizard/cli` scaffold — ships `safeFetch` as one of the 11 clean-room security primitives.
179
+ - OWASP SSRF prevention cheat sheet — https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html