Eine schmale sichtbare Naht über einer tiefen, unbeleuchteten Schichtstruktur
Sichtbar ist die Änderung. Entscheidend ist, was darunter liegt.

Zwei Zeilen, dreieinhalb Monate

Ein Sprachmodell hat ein Deploy-Skript umgeschrieben. Vorher lud das Skript eine ausdrückliche Liste von Dateien hoch, Datei für Datei benannt. Nachher spiegelte es das gesamte Projektverzeichnis und schloss davon aus, was auf einer Ausschlussliste stand. Auf dieser Liste stand Unordnung: Markdown-Dateien, ein Dokumentationsordner, .DS_Store. Niemand hat gefragt, welche Datei ein Geheimnis ist.

Eine Datei mit zwei API-Schlüsseln ging mit hoch und lag dreieinhalb Monate öffentlich abrufbar auf dem Webserver. Sie lieferte brav HTTP 200. Einer der Schlüssel wurde fremd verwendet, der Schaden lag im fünfstelligen Bereich. Kein Werkzeug hat in diesen dreieinhalb Monaten angeschlagen, und es gab auch keinen Grund dazu: syntaktisch war alles in Ordnung.

Das Diff war zwei Zeilen und sah harmlos aus. Was sich geändert hat, war nicht der Code, sondern die Standardannahme darunter: vorher war alles ausgeschlossen, was nicht ausdrücklich genannt war. Nachher war alles eingeschlossen, was nicht ausdrücklich genannt war.

Die Datei war korrekt in .gitignore eingetragen. Git-Schutz ist kein Deploy-Schutz, und diese Verwechslung ist so verbreitet, dass sie einen eigenen Prüfpunkt verdient. Gefunden habe ich die Datei nicht mit einem Werkzeug, sondern mit einer Frage. Genau darum geht es hier: Was findet KI in einer fremden Codebase, und wo hört sie auf?

Was die Werkzeuge zuverlässig finden

Zuerst die gute Nachricht, und sie ist größer als viele Skeptiker zugeben. Was vor fünf Jahren eine Woche Lesen war, ist heute ein Arbeitstag. Automatische Analyse ist in mehreren Bereichen besser als jeder Mensch, der unter Zeitdruck steht:

  • Abhängigkeiten und bekannte Lücken. Vollständig, aktuell, ohne Ermüdung. Ein Mensch übersieht in einer Liste von 900 Paketen das eine mit dem kritischen CVE. Ein Werkzeug nicht.
  • Toter Code. Nicht verwendete Exporte, unerreichbare Zweige, Module, die seit Jahren niemand importiert. Das findet sich statisch und ist eine der wenigen Aufräumarbeiten mit sofort messbarem Effekt.
  • Testabdeckung und Komplexität. Wo ist die Abdeckung dünn, und fällt das mit hoher Komplexität zusammen? Diese Schnittmenge ist der beste einzelne Fehlerprädiktor, den ich kenne.
  • Die Git-Historie. Der unterbewertetste Teil. Welche Dateien werden am häufigsten geändert, wo häufen sich Fehlerbehebungen, an welchen Personen hängt Wissen so, dass ein Kündigungsschreiben ein technisches Risiko wäre. Sprachmodelle sind hervorragend darin, aus zehn Jahren Commit-Nachrichten ein Muster zu lesen.

Wenn Sie diesen Teil nicht automatisieren, verschenken Sie Geld. Er ist die Pflicht, und er ist heute billig. Wer Ihnen dafür drei Wochen verrechnet, verkauft Ihnen Handarbeit an einer Stelle, an der Handarbeit keinen Mehrwert hat. Mehr dazu, welche Aufräumarbeit sich wirtschaftlich rechnet, steht in Technische Schulden abbauen.

Wo sie strukturell aufhören

Jetzt der Teil, an dem der Deploy-Fall hängt. Es gibt drei Kategorien von Befunden, die automatische Analyse nicht nur zufällig verpasst, sondern aus einem strukturellen Grund verpassen muss.

Die Bedeutung von Voreinstellungen

Ein Modell liest, was der Code tut. Der Wechsel von einer Erlaubnisliste zu einer Ausschlussliste ändert nicht, was der Code tut, sondern was er annimmt, wenn niemand etwas sagt. Beide Fassungen laden Dateien auf einen Server. Beide sind syntaktisch einwandfrei. Die eine ist im Zweifel still, die andere im Zweifel großzügig. Diesen Unterschied sieht man nicht im Diff, sondern nur, wenn man fragt, was passiert, wenn sich künftig jemand nicht meldet.

Invarianten, die nur in Köpfen stehen

In jeder gewachsenen Fachanwendung gibt es Sätze wie: dieses Feld darf nie leer sein, weil sonst die Abrechnung im nächsten Monat falsch läuft. Solche Regeln stehen selten im Code und fast nie im Kommentar. Sie stehen im Kopf des Entwicklers, der vor sechs Jahren den Fehler behoben hat. Ein Modell, das diese Regel nicht kennt, sieht eine unnötige Prüfung und schlägt vor, sie zu entfernen. Der Vorschlag ist sauber begründet, gut formuliert und falsch.

Ein Lichtkegel, der wenige Zellen eines dichten Rasters scharf zeichnet, während der Rest dunkel bleibt
Werkzeuge beleuchten einen scharfen Ausschnitt. Der Rest bleibt dunkel, und zwar nicht zufällig.

Der Grund hinter dem Umweg

Code sagt, was passiert, nicht warum. Wenn an einer Stelle eine merkwürdige Umgehung steht, liest ein Werkzeug einen Mangel und bietet eine Bereinigung an. Manchmal ist die Umgehung tatsächlich Schrott. Manchmal ist sie die Narbe eines Produktionsausfalls, und die Bereinigung stellt ihn wieder her. Die Unterscheidung steht in keiner Datei, sondern im Ergebnisprotokoll eines Vorfalls von 2019 und im Gedächtnis von zwei Menschen.

Dazu kommt eine Eigenschaft der Werkzeuge selbst, die in Sicherheitsfragen unangenehm ist: sie sind darauf trainiert, zuzustimmen und etwas zu liefern. Die Frage ist das so sicher? bekommt öfter ein Ja, als sie sollte. Wer genauer wissen will, wie sich das beim Programmieren mit KI auswirkt, findet das in Vibe Coding: Sicherheitsrisiken erkennen und in API-Key-Sicherheit ausführlicher.

Der Prüfpunkt, der fast überall etwas findet

Aus diesem Fall ist ein Prüfpunkt geworden, den ich seither in jedem Audit stelle. Er kostet zehn Minuten und findet bei fast jedem Kunden etwas. Der Grund ist immer derselbe: Geprüft wird .gitignore, und dort ist auch alles in Ordnung. Der Auslieferungsweg ist eine zweite Liste, und die sieht sich niemand an.

Fünf Fragen an Ihren Auslieferungsweg:

1. Ist Ihr Deploy eine Erlaubnisliste oder eine Ausschlussliste? Wenn Sie es nicht sofort beantworten können, ist es eine Ausschlussliste.
2. Wann wurde diese Liste zuletzt Datei für Datei gegen den tatsächlichen Verzeichnisinhalt gehalten? Nicht überflogen, sondern durchgegangen.
3. Steht dort .env oder .env*? Der erste Ausdruck trifft .env.local nicht.
4. Liegen Geheimnisse überhaupt in einem Verzeichnis, das ausgeliefert wird? Was nicht dort liegt, kann keine Liste vergessen.
5. Prüft nach jedem Deploy etwas automatisch nach, ob /.env, /.env.local und /.git/config öffentlich antworten? Erwartet sind 403 oder 404. Ein 200 ist kein Hinweis, sondern ein Vorfall.

Punkt fünf ist der wichtigste und zugleich der billigste. Eine Zeile mit curl nach dem Upload hätte die dreieinhalb Monate auf eine Minute verkürzt. Der Grund, warum sie gefehlt hat, ist nicht technisch: Die Ausschlussliste war vorher ausdrücklich geprüft worden. Geprüft wurde nur, ob Unordnung mitgeht, nicht ob Geheimnisse mitgehen. Ein Häkchen an der falschen Frage ist schlimmer als gar keins, weil es Sicherheit vortäuscht.

Wie ein Audit aussieht, das beides zusammenbringt

Daraus folgt eine klare Arbeitsteilung. Die Werkzeuge machen die Fläche, der Mensch macht das Urteil. Praktisch sieht die Aufteilung so aus:

Dimension Werkzeug liefert Mensch muss urteilen
AbhängigkeitenVollständige Liste bekannter LückenWelche davon in Ihrem Einsatzszenario überhaupt erreichbar ist
TestabdeckungProzentwerte je ModulOb die getesteten Pfade die wirtschaftlich teuren sind
Änderungs-HotspotsDateien mit höchster ÄnderungsrateOb dort Wertschöpfung stattfindet oder Reibung
Auslieferung und BetriebWenig bis nichtsAlles: Voreinstellungen, Geheimnisse, Rechte
Fachliche InvariantenNichtsAlles, und zwar nur im Gespräch zu heben
KI-Reife des TeamsNichtsWo KI-gestützte Entwicklung sofort trägt und wo sie gefährlich ist

Deshalb beginnt mein Codebase-Audit mit der Historie und nicht mit dem Quelltext, und deshalb gehören zwei Einzelgespräche mit Entwicklern fest dazu. Die vierte und fünfte Zeile der Tabelle bekommen Sie ausschließlich über Menschen, die in dem System gearbeitet haben.

Am dritten Tag steht bei mir eine Live-Vorführung: eine echte kleine Aufgabe aus Ihrem Backlog, in Ihrer Codebase, vor Ihrem Team, in 40 Minuten, ungeschnitten. Nicht weil es beeindruckt, sondern weil ein Bericht eine Behauptung ist und ein Durchlauf ein Beweis. Wenn ich Ihnen sage, dass KI-gestützte Entwicklung bei Ihnen sofort etwas bringt, sollten Sie das sehen dürfen statt es zu glauben.

Woran Sie ein schlechtes Audit erkennen

Der Markt füllt sich gerade mit Angeboten, die einen Werkzeug-Export mit einem Deckblatt versehen. Vier Merkmale unterscheiden das von einem Audit:

  • Der Bericht zählt statt zu gewichten. 300 Befunde nach Schweregrad sortiert führen dazu, dass niemand etwas tut. Fünf Risiken mit Auswirkung in Geschäftssprache führen zu einer Entscheidung.
  • Es fehlt die wirtschaftliche Einordnung. Ein Befund ohne Angabe, was er Sie heute an Entwicklungszeit kostet, ist eine Meinung. Gerechnet wird mit Ihren Zahlen, nicht mit Branchendurchschnitten.
  • Niemand steht mit Namen dahinter. Wenn nicht klar ist, wer geurteilt hat und wer im Ergebnisgespräch sitzt, ist die Empfehlung nicht belastbar.
  • Es steht „man könnte“ statt „ich würde“. Ein Audit, das sich nicht festlegt, verschiebt die Entscheidung zurück zu Ihnen, und dafür brauchen Sie niemanden.

Was bleibt

Die Werkzeuge sind in den letzten zwei Jahren dramatisch besser geworden, und ich setze sie täglich ein, auch in Kundenprojekten und in der Rolle als Interim CTO. Sie nehmen mir die Flächenarbeit ab und geben mir in einem Tag ein Bild, für das ich früher eine Woche gebraucht habe.

Was sie mir nicht abnehmen, ist die Frage, welche fünf Dinge im nächsten Jahr tatsächlich wehtun. Diese Frage beantwortet man nicht durch Lesen von Code, sondern durch Lesen von Annahmen. Der Deploy-Fall oben stand dreieinhalb Monate offen, weil niemand die eine Frage gestellt hat, die nicht im Diff steht. Genau diese Fragen sind der Ertrag eines Audits. Die Befundliste bekommen Sie heute fast geschenkt.