@aegis-scan/skills 0.1.1 → 0.2.1
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 +71 -20
- package/CHANGELOG.md +55 -0
- package/README.md +66 -18
- package/dist/bin.js +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +17 -1
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +9 -2
- package/dist/commands/list.js.map +1 -1
- package/package.json +3 -2
- package/sbom.cdx.json +1 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/SKILL.md +305 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/abmahn-templates.md +306 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/aegis-integration.md +241 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/audit-patterns.md +277 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/bgh-urteile.md +167 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/branchenrecht.md +285 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/checklisten.md +276 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/dsgvo.md +238 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/international.md +163 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/it-recht.md +267 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/strafrecht-steuer.md +193 -0
- package/skills/compliance/aegis-native/brutaler-anwalt/references/vertragsrecht.md +243 -0
- package/skills/defensive/README.md +33 -4
- package/skills/defensive/aegis-native/rls-defense/SKILL.md +174 -0
- package/skills/defensive/aegis-native/ssrf-defense/SKILL.md +179 -0
- package/skills/defensive/aegis-native/tenant-isolation-defense/SKILL.md +225 -0
- package/skills/mitre-mapped/README.md +36 -8
- package/skills/mitre-mapped/aegis-native/mapping-overview/SKILL.md +129 -0
- package/skills/mitre-mapped/aegis-native/t1078-valid-accounts/SKILL.md +136 -0
- package/skills/mitre-mapped/aegis-native/t1190-exploit-public-app/SKILL.md +108 -0
- package/skills/ops/README.md +39 -4
- package/skills/ops/aegis-native/escalation-runbook/SKILL.md +147 -0
- package/skills/ops/aegis-native/suppress-correctly/SKILL.md +196 -0
- 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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|