127 lines
4.7 KiB
Markdown
127 lines
4.7 KiB
Markdown
# Umsetzungsplan: GitHub Issues & PR Comments Scanner
|
||
|
||
## Zusammenfassung
|
||
Scan von öffentlichen GitHub Issue- und PR-Kommentaren nach geleakten API-Keys.
|
||
TruffleHog-Studien zeigen Zehntausende Secrets in GitHub-Kommentaren – eine bisher kaum gescannte Quelle.
|
||
|
||
## Warum Issues/Comments?
|
||
- User posten Keys in Issues ("mein Key funktioniert nicht: sk-ant-oat01-...")
|
||
- Keys in PR-Kommentaren, Code-Reviews, Fehlermeldungen
|
||
- Selbst nach Edit bleiben alte Versionen in der Comment-History sichtbar
|
||
- GitHub Code Search (`/search/code`) durchsucht **keine** Issues/Comments
|
||
- Unser bestehender GitHub-Scanner und Serper decken diese Quelle **nicht** ab
|
||
|
||
## API-Analyse
|
||
|
||
### GitHub Search Issues API ✅ (Hauptansatz)
|
||
```
|
||
GET https://api.github.com/search/issues?q="sk-ant-oat01"+in:comments&per_page=100
|
||
```
|
||
|
||
- Durchsucht Issue-Titel, Body UND Kommentare
|
||
- `in:comments` filtert auf Kommentare
|
||
- Gibt Issues zurück, nicht die Kommentare selbst
|
||
- Max 1000 Ergebnisse (10 Seiten à 100)
|
||
- **Rate Limit:** 30 Requests/Minute (authentifiziert), 10/min unauthentifiziert
|
||
|
||
### GitHub List Issue Comments API (Ergänzung)
|
||
```
|
||
GET https://api.github.com/repos/{owner}/{repo}/issues/comments?since=2024-01-01&per_page=100
|
||
```
|
||
|
||
- Listet alle Kommentare eines Repos (mit `since`-Filter für inkrementellen Scan)
|
||
- Max ~30.000 Kommentare pro Repo via REST
|
||
- Response enthält `body` → kann mit Regex gescannt werden
|
||
- Nützlich um **nach** dem Search-API-Treffer die tatsächlichen Keys aus den Comments zu extrahieren
|
||
|
||
### Drei Arten von Kommentaren
|
||
| Typ | API-Endpoint | Beschreibung |
|
||
|---|---|---|
|
||
| Issue Comments | `/repos/{owner}/{repo}/issues/comments` | Kommentare auf Issues UND PR-Diskussionen |
|
||
| PR Review Comments | `/repos/{owner}/{repo}/pulls/comments` | Inline-Code-Review-Kommentare |
|
||
| Commit Comments | `/repos/{owner}/{repo}/comments` | Kommentare auf einzelne Commits |
|
||
|
||
## Implementierungsplan
|
||
|
||
### Phase 1: Search Issues Scan
|
||
|
||
```csharp
|
||
private async Task<List<(string Key, string Url)>> ScanGitHubIssues(CancellationToken ct)
|
||
```
|
||
|
||
**Ablauf:**
|
||
1. **Issue Search** für jeden Key-Pattern-SearchTerm:
|
||
```
|
||
GET /search/issues?q="sk-ant-oat01"+in:comments&sort=created&order=desc&per_page=100
|
||
GET /search/issues?q="sk-ant-oat01"+in:body&sort=created&order=desc&per_page=100
|
||
```
|
||
2. Für jeden Treffer:
|
||
- Issue-`body` mit Regex scannen
|
||
- Kommentare des Issues abrufen:
|
||
```
|
||
GET /repos/{owner}/{repo}/issues/{number}/comments?per_page=100
|
||
```
|
||
- Jeden Kommentar-`body` mit Regex scannen
|
||
3. **PR Review Comments** für Treffer-Repos:
|
||
```
|
||
GET /repos/{owner}/{repo}/pulls/comments?per_page=100&since={last_scan}
|
||
```
|
||
4. Gefundene Keys mit HTML-URL des Kommentars zurückgeben
|
||
|
||
### Phase 2: Integration in RunScan
|
||
|
||
```csharp
|
||
// In RunScan(), nach GitHub Code Search:
|
||
if (mode != "web" && !string.IsNullOrWhiteSpace(_githubToken))
|
||
{
|
||
var issueKeys = await ScanGitHubIssues(ct);
|
||
allFoundKeys.AddRange(issueKeys.Select(k => (k.Key, k.Url, "github_issues")));
|
||
}
|
||
```
|
||
|
||
- **Mode `quick`:** Nur Search Issues API (schnell, max 10 Requests)
|
||
- **Mode `web`:** Kein Issue-Scan (gehört zu GitHub)
|
||
- **Mode `full`:** Search Issues + Comment-Scan der Treffer
|
||
|
||
### Phase 3: Deduplication mit bestehendem GitHub-Scan
|
||
|
||
Keys die bereits über GitHub Code Search gefunden wurden, werden über `_db.ScannedKeyExists()` dedupliziert.
|
||
Source wird als `"github_issues"` gespeichert (statt `"github"`), damit die Quelle unterscheidbar ist.
|
||
|
||
## Rate-Limit-Strategie
|
||
|
||
| API | Rate Limit | Strategie |
|
||
|---|---|---|
|
||
| Search Issues | 30 req/min | Max 10 Seiten × Anzahl Patterns = ~20 Requests |
|
||
| Issue Comments | 5000 req/h | Pro Treffer 1 Request, max 100 Treffer |
|
||
| PR Review Comments | 5000 req/h | Nur für Treffer-Repos |
|
||
|
||
**Gesamtverbrauch pro Full-Scan:** ~120-200 Requests (gut innerhalb der Limits)
|
||
|
||
**Wartezeiten:**
|
||
- Zwischen Search-Requests: 2s (30 req/min = 1 req/2s)
|
||
- Zwischen Comment-Requests: 1s
|
||
|
||
## Suchqueries
|
||
|
||
```csharp
|
||
private static readonly string[] IssueSearchQueries = {
|
||
"\"sk-ant-oat01\" in:comments",
|
||
"\"sk-ant-oat01\" in:body",
|
||
"\"sk-ant-api03\" in:comments",
|
||
"\"sk-ant-api03\" in:body",
|
||
"\"ANTHROPIC_API_KEY\" in:comments", // Bonus: env-var-Name → könnte Key im selben Comment haben
|
||
};
|
||
```
|
||
|
||
## Aufwandsschätzung
|
||
- **Implementierung:** ~250 Zeilen Code
|
||
- **Komplexität:** Mittel (mehrere API-Endpoints, Comment-Extraction)
|
||
- **Erwarteter Ertrag:** 🔥 Hoch (nachgewiesene Secret-Quelle, kaum gescannt)
|
||
|
||
## Risiken
|
||
- Search Issues API gibt max 1000 Ergebnisse → ältere Issues nicht erreichbar
|
||
- Kommentare können editiert/gelöscht sein → Key evtl. nicht mehr im Body
|
||
- Rate-Limits bei vielen Treffern → braucht gute Throttling-Logik
|
||
- Manche Keys sind absichtlich gepostet (Test-Keys, bereits revoked) → False Positives
|