von Hören

Technischer Forschungsbericht

Kontinuierliches Exposure Management für den Mittelstand

Architektur und erste Ergebnisse aus dem Produktivbetrieb

Autor
Welf von Hören
Herausgeber
von Hören Potential Ventures UG
Datum
Version
1.0

Dieser Bericht beschreibt die Architektur eines kontinuierlichen Exposure Managements, das wir für kleine und mittlere Unternehmen entwickelt haben, und wertet die ersten drei Betriebstage aus. Der Monitoring-Node verarbeitete in diesem Fenster 7.556 Meldungen aus öffentlichen Quellen und eigenen Scannern und ordnete sie dem Bestand von drei Projekten zu. Für den ersten Produktivkunden (Client A, SaaS-Plattform für Fitnessstudios) entstanden 941 Treffer; nach Triage blieben 22,7 % der geprüften Treffer als relevant übrig. Ein Fallbeispiel zeigt den Weg eines Befunds von der Aufzeichnung bis zur verifizierten Behebung. Alle Zahlen stammen aus der Datenbank und den Protokollen des Systems. Was wir noch nicht messen, kennzeichnen wir als solches.

Problem

Kleine und mittlere Unternehmen betreiben heute dieselbe Art von Infrastruktur wie Konzerne: Cloud-Server, Container, Software mit Hunderten Abhängigkeiten, Geräte im Feld. Sie haben aber selten ein Sicherheitsteam. Die Aufgabe, neue Schwachstellen gegen den eigenen Bestand zu prüfen, landet bei der IT oder bei einem Dienstleister, der viele Kunden parallel betreut.

Das gängige Instrument ist der periodische Penetrationstest. Er liefert eine Momentaufnahme. Zwischen zwei Tests vergehen oft zwölf Monate. In dieser Zeit erscheinen neue Schwachstellen, der Bestand ändert sich, und niemand gleicht beides ab. In den drei Beobachtungstagen dieses Berichts lieferten allein zwölf öffentliche Feeds 2.204 Meldungen. Ein Schwachstellenscanner verkürzt den Abstand, erzeugt aber ein zweites Problem: lange Listen. Jeder Treffer muss von Hand geprüft werden. Nutzen wir das Paket? Ist der Dienst erreichbar? Gibt es eine Korrektur? Diese Prüfung kostet Zeit, und deshalb bleibt sie liegen.

Drei Dinge fehlen: ein Bestand, der aktuell bleibt; eine Triage, die jeden Treffer gegen diesen Bestand bewertet; und ein Weg, der von der Bewertung bis zur verifizierten Behebung führt. Unsere Hypothese: Ein kleiner, kontinuierlich laufender Node pro Kunde kann diese drei Dinge leisten, wenn eine KI-Triage den Abgleich übernimmt und Menschen nur noch die Behebung freigeben.

Methode und Architektur

Das System heißt intern vulnwatch. Es ist in Python geschrieben, läuft als systemd-Dienst auf einem Linux-Server und hält seinen Zustand in einer SQLite-Datenbank. Ein Timer startet alle fünf Minuten einen Lauf. Jeder Lauf durchläuft die Stufen Ingest, Abgleich, Triage, Meldung. Schwere Quellen laufen seltener: Repository-Inventar stündlich, Host-Reports alle drei Stunden, Außenscan, Secret-Scan und CI-Audit täglich.

Ingest: welche Daten das System liest

  • CISA KEV (Known Exploited Vulnerabilities, JSON-Katalog): Treffer per Hersteller- und Produktabgleich; jeder Treffer gilt als kritisch.
  • OSV (querybatch und Detailabfrage): Advisories zu jedem Paket aus den Lockfiles des Kunden. Zehn Lockfile-Formate werden gelesen (npm, bun, pnpm, yarn, requirements, poetry, uv, Cargo, go.sum).
  • Aikido-Malware-Listen für npm und PyPI: eine bösartige Version im Bestand gilt als kritisch.
  • Zwölf RSS-Feeds, darunter CERT-Bund WID, oss-security, Node.js Security, Hersteller-Research und Fachpresse. Stichwortabgleich gegen 84 Stack-Begriffe.
  • Host-Agent auf jedem Kundenserver: Trivy-Scan des Dateisystems und der laufenden Container, dazu die Liste offener Ports (ss -ltnup). Der Node holt die Reports per SSH ab; der Agent öffnet keinen Rückkanal.
  • Außensicht: nmap über die 1.000 häufigsten TCP-Ports (IPv4 und IPv6), Shodan InternetDB, Certificate-Transparency-Logs (crt.sh), TLS-Gültigkeit und Ablauf.
  • Secrets und CI: gitleaks über Bare-Mirrors aller aktiven Repositories, zizmor über GitHub-Actions-Workflows.

Der erste Lauf jeder Quelle ist eine Baseline. Sie erzeugt keine Warnung, sondern einen Backlog, den ein KI-Modell zu einer Liste der zwanzig wichtigsten Maßnahmen verdichtet. Erst Änderungen gegenüber der Baseline lösen Meldungen aus.

Triage: Abgleich gegen den Bestand

Jeder neue Treffer geht in Paketen von höchstens 25 Stück an eine Triage-Instanz. Das ist ein Claude-Modell im Headless-Betrieb mit eingeschränkten Rechten: nur lesender Zugriff, kein Zugriff auf Konfiguration oder Schlüssel, GitHub nur über einen GET-only-Wrapper. Als Kontext erhält es eine gepflegte Beschreibung des Bestands (Server, Dienste, Netzgrenzen, Abhängigkeiten) und die Inventar-Tabellen. Feed-Texte sind als nicht vertrauenswürdig deklariert; Anweisungen darin werden ignoriert. Pro Treffer entsteht ein strukturiertes Urteil: applies (ja, nein, unklar), Schwere, Begründung in höchstens drei Sätzen, empfohlene Maßnahme. Fällt die Triage aus, eskalieren kritische Treffer aus KEV, OSV, Malware-Listen, Secret- und Host-Scan trotzdem.

Routing, Meldung, Behebung

Eine Registry ordnet Repositories, Hosts, Adressen und Domains je einem Projekt zu. Treffer werden zur Abfragezeit über ihre Assets geroutet; jedes Projekt hat eine eigene Warteschlange. Die Warteschlange enthält nur geprüfte, strukturierte Felder. Freitext aus Advisories gelangt nie ungefragt in den Arbeitsauftrag eines Agenten. Meldungen gehen ab Schwere „high“ per E-Mail, Push nur bei „critical“, dazu ein Tagesbericht um 07:30 und ein Wochenbericht. Ein Dispatcher auf einer Arbeitsstation öffnet pro Projekt eine Sitzung, in der ein Agent den Befund auf dem Kundensystem nachstellt, einen Pull Request mit Tests vorbereitet und das Ergebnis in einem Remediation-Protokoll festhält. Änderungen an Produktivsystemen setzen die Freigabe des Kunden voraus. Ein Fund schließt sich, wenn der Scanner ihn nicht mehr meldet, oder ein Mensch verwirft ihn mit Begründung.

Die Leistungsstufen Monitor (überwachen und melden), Respond (getestete Korrektur liefern) und Managed (vereinbarte Korrekturen einspielen) unterscheiden sich nur darin, wie weit dieser letzte Schritt reicht.

Architektur des Monitoring-Nodes Öffentliche Quellen und Kundensysteme fließen in einen Monitoring-Node. Dort gleichen Module die Daten gegen den Bestand ab, eine KI-Triage bewertet Treffer, Ergebnisse landen in SQLite, werden pro Projekt in Warteschlangen geroutet, gemeldet und auf einer Arbeitsstation validiert und behoben. Öffentliche Quellen CISA KEV cisagov/kev-data OSV querybatch + /vulns/{id} Aikido Malware-Listen npm + PyPI 12 RSS-Feeds CERT-Bund, oss-security, … GitHub API Lockfiles, Mirrors, Workflows Shodan · crt.sh InternetDB, CT-Logs: Außensicht Kundensysteme agent/install.sh Trivy rootfs + Container ss -ltnup (offene Ports) alle 3 h · nur Pull per SSH Forced Command: tar reports Monitoring-Node (VPS) · Timer alle 5 min Ingest & Abgleich gegen Bestand vulnwatch.py KEV · OSV · Aikido · RSS · Inventar hosts.py Agent-Reports, Pakete, Ports surface.py nmap, Shodan, CT-Logs, TLS leaks.py gitleaks über Mirrors ci.py zizmor (GitHub Actions) xintel.py · bookmarks.py X-Signale Erstlauf = Baseline, kein Alarm Triage core.claude() Headless, nur lesend Kontext: STACK.md + Inventar · Feed-Text = untrusted Urteil: applies · Schwere · Grund · Maßnahme Zustand core.py → SQLite hits · inventory · seen · kv Lebenszyklus: new → triaged → resolved / dismissed Meldung digest.py E-Mail ab high Push nur critical Routing projects.py projects.json Queue je Projekt Backlog & Berichte backlog.py Top-20 aus Baseline Tagesbericht 07:30 · Wochenbericht montags Signierter Feed Hub→Node: Entwurf, noch nicht gebaut Validierung & Behebung Arbeitsstation bin/sicherheit-dispatch Queue: nur Lesezugriff eine Sitzung je Projekt Auftrag ohne Freitext Nachstellen auf Kundensystemen mit schriftlichem Auftrag Versionsstand, Konfiguration, Nachbau im Test Behebung Pull Request + Tests Firewall, Bindung, Updates Protokoll: docs/security/ Freigabe für Prod: Kunde Schließen: Scanner oder dismiss Stufen Monitor überwachen, melden Respond getestete Korrektur liefern Managed vereinbarte Korrekturen einspielen
Abb. 1 — Modul-Layout des Systems, Stand 25. Oktober 2026. Kästen tragen die realen Modulnamen. Gestrichelt: Rückweg der Validierung zu den Kundensystemen und die Übergabe an die Leistungsstufen.

Erste Ergebnisse

Der Node läuft seit dem 22. Oktober 2026, 08:43 UTC. Dieser Bericht wertet den Stand vom 25. Oktober 2026, 11:37 UTC aus: ein Fenster von drei Tagen und drei Stunden, also noch keine volle Woche. In dieser Zeit startete der Timer 591 Läufe ohne einen Ausfall der Dienst-Einheit. Die erste Produktivumgebung ist Client A, eine SaaS-Plattform für Fitnessstudios mit Kiosk-Geräten in den Studios. Der Betreiber hat die Überwachung und die aktive Prüfung schriftlich beauftragt; das System betreibt die von Hören Potential Ventures UG. Derselbe Node überwacht auch unsere eigene Infrastruktur und ein zweites Kundenprojekt.

Tabelle 1 — Client A im Beobachtungsfenster 22.–25. Oktober 2026 (3 d 3 h). Quelle: SQLite-Datenbank und systemd-Journal des Nodes.
KennzahlWertAnmerkung
Erfasster Bestand2 Server · 7 Repositories · 2 Domains10.311 Pakete auf den Servern (Trivy), 771 Pakete in Lockfiles
Meldungen gesamt, alle Projekte7.556inkl. Erstaufnahme; davon 2.204 aus RSS-Feeds, 1.756 KEV-Einträge, 1.957 Host-Pakete
Treffer gegen Bestand Client A941Host-Pakete 799 · Secret-Scan 73 · Abhängigkeiten 60 · CI 8 · Außensicht 1
Scanner-Schwerecritical 42 · high 860 · moderate 27 · low 12vor Triage; 785 davon Baseline
Triagiert44zutreffend 7 · unklar 3 · nicht zutreffend 34
Anteil relevant nach Triage22,7 %(7 + 3) / 44; alle Projekte: 34,7 % (67 / 193)
Geschlossen11584 automatisch nach Rescan · 29 Secret-Funde tot, Dummy oder Fehlalarm · 2 beabsichtigt
Median Erkennung → Schließung1,7 hn = 84, automatisch geschlossene Funde; triagierte Funde n = 3 (0,1 h, 6,5 h, 21,8 h), zu klein für einen Median
Versendete Warnungen1davon Fehlalarm 1: neuer Hostname im CT-Log, vom Betreiber beabsichtigt
Zeit bis Triagen/a (noch nicht erhoben)die Datenbank speichert keinen Triage-Zeitstempel
Offene relevante Funde7in Bearbeitung; Stand 25. Oktober 2026, 11:37 UTC

Drei Beobachtungen. Erstens: Die Baseline dominiert. 785 der 941 Treffer stammen aus dem ersten Scan und sind alte, bekannte Pakete ohne Korrektur im Distributions-Repository. Das System meldet sie nicht, sondern verdichtet sie zu einem Backlog. Zweitens: Die Triage entfernt den größten Teil des Rauschens. Von 44 geprüften Treffern stufte sie 34 als nicht zutreffend ein, zum Beispiel weil der verwundbare Codepfad nicht erreichbar ist oder das Paket nur in einer Entwicklungsumgebung liegt. Drittens: Der Secret-Scan ist der lauteste Scanner. Über alle Projekte prüften wir 280 Funde aus fünf privaten Repositories gegen die laufenden Systeme: null lebende Zugangsdaten, acht tote, zehn Testwerte, 262 Fehlalarme.

Über alle drei Projekte verarbeitete der Node 3.010 Treffer, triagierte 193, schloss 307 automatisch (Median 4,8 h, n = 307) und versendete 13 Warnungen sowie zwei Tagesberichte.

Fallbeispiel: Datenbankport auf dem Staging-Server

Befundklasse. Ein Datenbankdienst war an alle Netzwerkschnittstellen gebunden. Die Cloud-Firewall ließ den Port von außen für genau eine Adresse zu, den Betriebsserver des Dienstleisters. Zugleich erlaubte die Richtlinie des Overlay-Netzes jedem Gerät im Netz den Zugriff, darunter den Kiosk-Rechnern in den Studios. Die Datenbank hing damit an zwei Regeln, die niemand prüfte. Eine Änderung an einer davon, oder ein kompromittiertes Gerät, hätte den direkten Zugang geöffnet.

  1. Der Host-Agent liefert seinen ersten Report. Die Portliste zeigt den Datenbankport auf der öffentlichen Schnittstelle. 16 Sekunden später sieht der Außenscan den Port von außen offen. Beides ist Baseline: kein Alarm, Eintrag im Bestand.
  2. Bei der Durchsicht der Baseline und der Overlay-Netz-Richtlinie wird der Befund priorisiert. Ein Abgleich der Firewall-Regeln bestätigt die Ausnahme; eine Messung aus dem Overlay-Netz bestätigt, dass Kiosk-Geräte den Port erreichen. Die Regeln werden als Beweismittel gesichert.
  3. BehebungVier Änderungen, als Pull Request mit Rollback-Kopien: Firewall-Regel gelöscht; Datenbank hört nur noch auf localhost und der Overlay-Adresse; Zugriffsliste auf einen Benutzer von einer Adresse mit TLS und SCRAM beschränkt; ein sysctl-Eintrag, damit der Dienst die Overlay-Adresse auch nach einem Neustart vor dem Netz-Daemon binden kann. Die Richtlinie des Overlay-Netzes folgt am selben Tag als Policy-as-Code mit Testblock.
  4. VerifikationVerbindungsversuche von zwei Standorten laufen in ein Timeout (IPv4 und IPv6). SSH funktioniert weiter. Der berechtigte Client verbindet sich über das Overlay-Netz mit TLS. Der Health-Endpunkt der Anwendung antwortet mit 200.
  5. Der nächste Host-Report meldet eine neue Bindung: derselbe Port, jetzt auf der Overlay-Adresse. Das System erzeugt einen Treffer der Schwere „high“, die Triage stuft ihn als zutreffend ein. Vier Minuten später wird er mit Begründung als beabsichtigt geschlossen. Der Scanner hat die Korrektur unabhängig bestätigt.

Die Korrektur stand rund 30 Stunden nach der ersten Aufzeichnung. Zwei Lehren: Eine Baseline ohne Alarm ist richtig, damit der erste Tag nicht in Hunderten Meldungen untergeht; sie braucht aber eine zügige menschliche Durchsicht. Und der Scanner, der den Befund fand, ist auch der beste Zeuge für die Behebung.

Grenzen und nächste Schritte

Was dieser Bericht nicht zeigt

  • Kurzes Fenster. Drei Tage sind eine Stichprobe, keine Statistik. Die Baseline prägt alle Zahlen. Eine zweite Auswertung nach 30 Tagen ist geplant.
  • Ein Node, drei Projekte. Die Zielarchitektur sieht einen Node pro Kunde und einen zentralen Hub vor, der nur signierte öffentliche Meldungen verteilt. Heute liest ein Node, den wir betreiben, die Quellen direkt und überwacht unsere Infrastruktur und zwei Kundenprojekte gemeinsam. Der signierte Hub-Feed ist entworfen, nicht gebaut.
  • Stille Baseline. Das Fallbeispiel zeigt die Kehrseite: Ein Befund aus dem ersten Scan erzeugt keine Warnung. Die Durchsicht der Baseline ist heute ein manueller Schritt.
  • Fehlende Zeitstempel. Die Datenbank hält fest, wann ein Treffer entsteht und wann er schließt, aber nicht, wann die Triage ihn bewertet hat. Zeit bis Triage und Kosten pro Triage sind deshalb nicht messbar.
  • Bestandsbeschreibung von Hand. Der Kontext der Triage ist ein gepflegter Text plus Inventar-Tabellen, kein strukturierter Asset-Graph. Veraltet der Text, sinkt die Qualität der Urteile.
  • Blinde Flecken. Kein EPSS im Produktiv-Node (nur im Prototyp). Keine Inventarisierung der Arbeitsstationen und der Windows-Kiosks. Treffer aus Nachrichten-Feeds ohne Asset-Bezug laufen nur in das Standardprojekt. Der Host-Scanner sieht die Laufzeitumgebung einer Anwendung nicht, wenn sie als einzelne Binärdatei installiert ist.
  • KI-Urteile sind fehlbar. Die Triage kann einen Treffer falsch einstufen. Der Fail-safe eskaliert kritische Funde auch ohne Urteil; eine systematische Messung der Urteilsqualität gegen eine menschliche Zweitmeinung steht aus.
  • Behebung braucht Freigabe. Mehrere vorbereitete Korrekturen warten auf die Freigabe des Betreibers für die Produktivumgebung. Die Zeit zwischen „Korrektur bereit“ und „eingespielt“ liegt beim Kunden und erscheint in keiner Kennzahl.

Nächste Schritte

  1. Triage-Zeitstempel und Token-Kosten pro Lauf in der Datenbank erfassen.
  2. Einen dedizierten Node für Client A ausrollen; Hub-Feed mit Signatur bauen.
  3. Baseline-Durchsicht automatisieren: der Backlog-Lauf eskaliert Funde zur Netzexposition sofort.
  4. EPSS in die Priorisierung des Produktiv-Nodes übernehmen.
  5. Urteilsqualität messen: eine Stichprobe von Triage-Urteilen gegen manuelle Prüfung, mit Fehlerquote je Klasse.
  6. Bericht v1.1 nach 30 Tagen Betrieb mit denselben Kennzahlen.