Nach sieben Sessions statischer Analyse — SCA, License Compliance, SAST, Container Scanning, Secret Detection — wechseln Patrick Steger und ich auf die dynamische Seite der Pipeline. In Teil 8 ergänzen wir Dynamic Application Security Testing in unserer GitHub-Actions-Pipeline. DAST startet die Anwendung und greift sie dann an. GitHub liefert das nicht out of the box, also bauen wir eine Community-Action auf Basis von OWASP ZAP ein — und sind ehrlich, wo dieser Ansatz für Enterprise-Use an Grenzen stösst.
Was DAST für uns bedeutet#
Bei Dynamic Application Security Testing starten wir unsere eigene Anwendung und greifen sie dann an — automatisiert, versteht sich. Wir brauchen ein Tool, das eine Anwendung scannt und angreift, die entweder in der Pipeline läuft oder irgendwo im Internet bzw. on-premises. GitHub liefert kein eigenes DAST-Feature, also gehen wir in den Marketplace und suchen eine passende Action. Wir landen bei action-full-scan vom ZAP Team — basierend auf dem bekannten Open-Source-Tool OWASP ZAP.
Wir nutzen die Action out of the box, ohne eigene ZAP-Konfiguration. Für eine Enterprise-Anwendung reicht das selten — saubere ZAP-Konfiguration ist ein eigenes Projekt. Interessanterweise lieferte die Standard-Konfiguration in unserem Fall mehr und bessere Findings als auf der anderen Plattform, die wir vorher untersucht hatten.
Vorab: Die Schwächen#
Bevor wir den Workflow zeigen, benennt Patrick die Limitationen ehrlich. Erstens und am schlimmsten: Die ZAP-Findings sind im GitHub Vulnerability Management UI nicht sichtbar. Der Grund ist fehlender SARIF-Support — SARIF ist das Format, das GitHub erwartet, um Findings im Security Dashboard darzustellen. Zweitens haben wir die ZAP-Konfiguration nicht angepasst, also sind die Findings teilweise zufällig. Drittens testen wir gegen einen Docker-Container, der innerhalb der Pipeline gestartet wird, statt gegen ein echtes Cloud-Deployment. ZAP kann selbstverständlich auch eine deployte URL scannen — wir haben den Deploy-zu-Azure-Schritt nur weggelassen, um die Demo fokussiert zu halten.
Der Workflow#
Der DAST-Workflow lässt sich auf zwei Wegen triggern: manuell über workflow_dispatch oder als Teil der Gesamtpipeline über workflow_call. In beiden Fällen erwartet er einen Parameter — den Image Tag — plus die zwei bekannten Environment-Variablen für Container Registry und Image Name.
Der Job läuft auf ubuntu-latest und macht Folgendes: Repository auschecken, in die Registry einloggen, Image pullen, Container mit docker run starten, warten bis er hochgekommen ist und prüfen, ob er sinnvoll antwortet. Mit der laufenden Anwendung starten wir den ZAP-Scan über action-full-scan. Wir geben die Ziel-URL an und übergeben ein paar CLI-Optionen — unter anderem einen zusätzlichen Ajax Spider, um mehr Endpoints zu finden, und ein reduziertes Log Level, damit die Console lesbar bleibt.
Wir deaktivieren ausserdem eine Option, die sonst für jeden Scan ein GitHub Issue öffnen würde. Für ein Solo-Projekt mag das passen; im Enterprise-Kontext ist es unbrauchbar. Nach dem Scan laden wir den HTML-Report als Workflow-Artifact hoch und stoppen den Container. Wir hätten lieber SARIF hochgeladen, aber zum Aufnahmezeitpunkt war das von der Action nicht unterstützt und hätte selbst entwickelt werden müssen.
Aufruf aus der Hauptpipeline#
Der DAST-Workflow ist im Orchestrator als Job verdrahtet, der von build und docker abhängt. Er ruft den Workflow auf, den wir gerade definiert haben, übergibt die Secrets und konsumiert den Output image-tag des Docker-Jobs — so testet er genau das Artefakt, das upstream gebaut wurde.
Der Report#
Wenn die Pipeline läuft, erscheint der neue DAST-Job in der Run-Ansicht. Das Log zeigt das Registry-Login, den docker run, den Wait-and-Probe-Schritt und dann den Full ZAP Scan mit der exakten Kommandozeile und den wichtigsten Findings auf WARN-Level. Am Ende wird der HTML-Report als Artifact angehängt.
Im Report sehen wir sofort ein echtes Finding — ein Cross-Site-Scripting-Issue auf einem URL-Parameter. Wir wissen aus dem Source Code, dass die Vulnerability echt ist — der Scanner hat seinen Job also gemacht. Der Haken bleibt: Lieferform ist nur eine HTML-Datei. Kein Triage Flow, kein “Dismiss als False Positive”, keine Integration mit dem Rest der GitHub Security.
Die Issue-Option ist nicht die Antwort#
Es gibt ein Flag in der Action, das die Findings als GitHub Issue ablegt. Wir probieren es aus — und prompt entsteht ein Issue ZAP Full Scan Report mit allen Problemen. Sieht für dreissig Sekunden hilfreich aus. Dann merkst du, dass jeder Run ein neues Issue erzeugt, ohne Erinnerung daran, was du schon gefixt oder als nicht relevant markiert hast. Im Enterprise-Setting wird das sofort zu Lärm und nach wenigen Tagen ignoriert. Was wir tatsächlich wollen, ist ein Eintrag im Security Tab — wie bei Code Scanning — wo Findings First-Class-Objekte sind, die man bewirtschaften kann. SARIF-Support wäre der Schlüssel dazu.
Recap#
DAST mit GitHub heute: Container mit der Anwendung starten (in der Pipeline für die Demo, in der Cloud für echte Systeme), zweiten Container mit OWASP ZAP starten, der ihn angreift, Findings sammeln, HTML-Report hochladen. Es funktioniert, es findet echte Vulnerabilities, und es hat zwei reale Schwächen — DAST ist schwierig sauber zu konfigurieren, und die GitHub-seitige Integration beschränkt sich auf ein HTML-Artifact oder ein lautes Auto-Issue. In der nächsten Session schauen wir uns Vulnerability Management an.
Key Takeaways#
GitHub hat kein eigenes DAST. Du gehst in den Marketplace. Die Community-Action
action-full-scanmit OWASP ZAP ist die praktische Wahl heute — out of the box für die Demo, für ein echtes Produkt deutlich getunt.DAST braucht ein laufendes Ziel. Wir starten den Container in der Pipeline, um die Demo einfach zu halten. In einer echten Enterprise-Pipeline wird der Container zuerst in eine Cloud-Umgebung deployed, und ZAP scannt die Live-URL.
Ohne SARIF kein natives Dashboard. Ohne SARIF-Output erscheinen die Findings nicht im GitHub Vulnerability Management. Du bekommst ein HTML-Artifact — okay zum Reinschauen, nicht für Triage at Scale.
Die Auto-Issue-Option ist eine Falle. Pro Scan ein GitHub Issue heisst, jeder Run erzeugt alles erneut, was du bereits triagiert hast. Eine Option für Mini-Projekte — in einer Enterprise-Pipeline auf keinen Fall einschalten.
Wait-and-Probe vor dem Scan. Container starten, warten, prüfen, ob er wirklich antwortet. Sonst scannt ZAP nichts und du shippst eine grüne Pipeline, die nichts bewiesen hat.
Default-ZAP-Konfiguration ist ein Startpunkt, kein Ziel. Sie hat in unserer Demo ein echtes XSS gefunden — ermutigend. Aber hochwertiges DAST in Produktion braucht bewusstes ZAP-Tuning. Plane das als eigenes Arbeitspaket ein.
