Max Nardit
← Artikel
11 mindev

Angriffsfläche reduzieren mit Claude Code: Anthropics drei Durchläufe auf meiner eigenen Website und eine vierte Frage, die sie nicht stellen

Anthropics Skill ist nicht veröffentlicht, die Methode lässt sich an einem Nachmittag nachbauen, und das Schwierige ist die Wahl, worauf du sie richtest. Auf meiner Website war das nützlichste Ergebnis eine kaputte Verifizierungsdatei, und die Lücke, die zählte, steckte in einer Deploy-Einstellung, die meine drei Durchläufe nie angesehen haben.

Inhalt

Am 20. Oktober hat Anthropics Frontier Red Team eine Methode veröffentlicht, die Claude eine andere Frage stellt. Sie fragt nicht, wo der Bug steckt, sondern welchen Code ein Angreifer erreichen kann, obwohl nichts diese Erreichbarkeit braucht. Das Team hat sie über 25 Open-Source-Projekte laufen lassen, zurück kamen 493 Befunde, und der Fall, mit dem der Beitrag einsteigt, ist OpenSSH: Dort waren in einer Standardinstallation rund 4.500 Zeilen experimenteller Post-Quanten-Code vor der Authentifizierung erreichbar.

Ich habe die Discovery-Hälfte der Methode auf dem einzigen öffentlichen System wiederholt, das ich testen kann, ohne jemanden zu fragen: dieser Website. Drei Durchläufe, jeder in frischem Kontext, die Befunde gegen einen lokalen Production-Build nachverfolgt. Das hat keine 25 Minuten Gesamtlaufzeit gedauert. Das Nützlichste, was dabei herauskam, war ein Bug, der mit Angriffsfläche nichts zu tun hatte, und das schlimmste Leck, das ich den ganzen Monat hatte, lag an einer Stelle, die keiner der drei Durchläufe ansieht. Beides zeigt: Die Methode findet, worauf du sie richtest, und das Richten ist dein Job.

Was ist Anthropics Methode zur Reduktion der Angriffsfläche (attack surface reduction) mit Claude?

Drei Fragen in drei Durchläufen, und jeder beginnt mit einem leeren Kontextfenster, abgesehen von einer kurzen Übergabe aus dem vorherigen. Der erste sucht Code, den die Standardkonfiguration für jeden erreichbar macht und den kein vorgesehenes Feature nutzt. Der zweite sucht Code, der vor einem harten Gate läuft, etwa der Authentifizierung oder einem Zustandswechsel im Protokoll, in beliebiger Konfiguration. Der dritte sucht Optionspaare, die eine Sicherheitskontrolle stillschweigend abschalten oder schwächen. Dass daraus keine Liste von Vermutungen wird, liegt am Bestätigungsschritt:

In every pass, Claude creates an inventory of the entry points from the
code and confirms each finding with a dynamic trace of the program. For
default configuration findings, it designs and implements a gate and
ensures that this causes no change in the program’s default behavior. It
does so by running the project's own test suite (along with a black box
regression suite) against the baseline; it requires modified builds to
have identical results.

Jedes Gate, das eine Nicht-Standardkonfiguration verändern würde, wird einem Menschen zur Entscheidung vorgelegt. Das ist der richtige Instinkt: schließen, was der Standard nie nutzt, und alles, was jemand nutzen könnte, dem Eigentümer überlassen.

Was haben Anthropics Attack-Surface-Durchläufe in OpenSSH gefunden, und was lässt der Beitrag weg?

Die zentralen Zahlen: 493 Befunde in 25 Projekten und über fünf Millionen Codezeilen, aus einem Inventar von mehr als 17.000 Konfigurationsoptionen, 3.842 davon sicherheitsrelevant. Die interessanteste Klasse kam aus dem dritten Durchlauf:

Claude found 162 security sensitive configuration combinations that were
accepted both without an error or warning and without any documentation
of the expected behavior of their interaction. In 94 of those cases, the
combination silently turned off a security control.

Ein Muster tauchte in vier Projekten auf: eine Deny-Regel, als Hostname geschrieben, bei abgeschalteten Reverse-DNS-Lookups. Der Server vergleicht dann ein Hostname-Muster mit einer IP-Adresse, die Regel kann nie greifen, und die Deny-Liste lässt alles durch (fail-open). Ein anderer Konflikt ließ einen Server, der Client-Zertifikate verlangte, jeden akzeptieren; dieser Konflikt steckte seit 21 Jahren im Code.

OpenSSH ist die Fallstudie. In 10.4 hat sshd jeden Schlüsseltyp geparst, den der Client schickte, und bei Zertifikaten die CA-Signatur geprüft, bevor er prüfte, ob dieser Schlüsseltyp überhaupt erlaubt war. ML-DSA-44 war standardmäßig nicht aktiviert, und der Code war trotzdem erreichbar, selbst wenn der Algorithmus ausdrücklich ausgeschlossen war. Anthropic beziffert das auf etwa 16 % von OpenSSHs eigenem Pre-Authentication-Code in einem Standard-sshd.

Release 10.5 hat die Prüfung vor das Parsen gezogen. Claude fand dann zwei Lücken in dieser Prüfung: Der angekündigte Algorithmus und der geparste Schlüsseltyp konnten sich unterscheiden, und CA-Schlüssel von Zertifikaten liefen weiterhin zuerst durch die volle Verifikation. Der Fix, der in 10.6 ausgeliefert wurde, setzt die Prüfungen in den Parser und hat ungefähr ein Fünftel des Codes entfernt, den ein nicht authentifizierter Client vorher erreichen konnte. Achte darauf, was er nicht getan hat: den ML-DSA-Code löschen. Er hat diesen Code für jemanden unerreichbar gemacht, der noch nicht reingelassen wurde.

Was der Beitrag weglässt, zählt genauso. Es gibt keine False-Positive-Rate für die 493, keine Zahl der Befunde, die Maintainer außerhalb von OpenSSH angenommen haben, und keine Kostenangabe, obwohl die Autoren sagen, dass Claude das wirtschaftlich erledigt. Für die Befunde, die ein Gate bekamen, sagen sie offen, dass keiner der Befunde für sich genommen sofort ausnutzbar gewesen wäre. Das liegt in der Natur der Methode und ist keine Schwäche: Du verkleinerst die Fläche, bevor jemand den Exploit schreibt, also ist die Zahl, auf die du achten solltest, der Code, den ein Außenstehender nicht mehr erreicht, und nicht die Zahl gefundener Schwachstellen.

Ist Anthropics Skill für Attack Surface Reduction veröffentlicht?

Mit dem Beitrag vom 20. Oktober nicht. Er beschreibt die drei Durchläufe, zusammengefasst in einem wiederverwendbaren Claude-Skill, und sagt, dass das Team ihn in OSS-Scanner integriert, verlinkt aber kein Repository und veröffentlicht keine Prompts. Was folgt, ist also ein Nachbau der Methode aus ihrer Beschreibung, und die Formulierung jedes Durchlaufs stammt von mir, nicht von Anthropic. Der Nachbau ist nicht schwer, denn die Methode ist vor allem Disziplin: getrennte Kontexte, ein laufender Build, ein Trace pro Befund, die projekteigenen Tests als Baseline.

Wie führst du Attack Surface Reduction in Claude Code durch?

Bau das echte System lokal und richte jeden Durchlauf darauf. Für eine Next.js-Website heißt das: ein Worktree auf dem Commit, den du testen willst, ein Production-Build und ein Server, der an das Loopback-Interface auf einem freien Port gebunden ist (standardmäßig lauscht next start auf allen Interfaces):

shell
git worktree add --detach ../asr HEAD
cd ../asr && npm ci && npm run build
npx next start -H 127.0.0.1 -p 3130

Dann lass die projekteigenen Tests gegen diesen Server laufen, bevor irgendein Durchlauf startet, damit es eine Baseline gibt, mit der du einen Eingriff vergleichen kannst. Hier waren das die Testskripte für die Markdown- und MCP-Endpunkte, die das Repository schon hat; beide liefen durch. Der Layout-Test ließ sich in dieser Umgebung nicht ausführen, also sage ich das hier, statt ihn stillschweigend wegzulassen.

Jeder Durchlauf geht an einen eigenen Claude-Code-Subagenten, damit kein Durchlauf die Schlussfolgerungen eines anderen erbt; ich habe die drei parallel laufen lassen. Alle drei Prompts teilen dieselben Regeln: den Worktree lesen, nichts ändern, Requests nur an localhost schicken, einen Befund nur zählen, wenn ein curl-Trace zeigt, dass der Pfad erreicht wird, und für jeden Befund benennen, was du entfernen würdest und welcher Test oder Request zeigt, dass das Standardverhalten erhalten bleibt. Die Frage von Durchlauf 1, gekürzt aus dem Prompt, mit dem er lief:

Which code is reachable in the DEFAULT configuration (no special env
vars, no flags, a normal production build) that does NOT need to be
reachable for the site to do its job? "Does not need to be reachable" =
a route, method, parameter, header path, rewrite, debug branch, or file
that is served but serves no purpose for those jobs.

Zwei Details in diesem Prompt tragen die Hauptlast. Er nennt die Aufgaben der Website, einschließlich der Endpunkte, die absichtlich öffentlich sind, damit der Durchlauf Oberflächen, die absichtlich maschinenlesbar sind, nicht als Ballast markiert. Und er sagt dem Durchlauf, dass ich Code lieber entferne, als Schutzprüfungen hinzuzufügen, und das verändert, wie ein vorgeschlagener Fix aussieht.

Mein Lauf blieb an einer Stelle hinter dem von Anthropic zurück: Er umfasste Discovery und Vorschläge. Während der Durchläufe wurde kein Eingriff vorgenommen, also ist die Regressionshälfte von Anthropics Schleife, modifizierter Build gegen Baseline, für diese Befunde noch nicht gelaufen.

Was findet Durchlauf 1 der Attack Surface Reduction auf einer kleinen Next.js-Website?

Durchlauf 1 dauerte fünfeinhalb Minuten, die Test-Baseline eingeschlossen, und bestätigte sechs Befunde plus einen Fall von totem Code. Der Art nach sind das Aliase, auf die nichts verlinkt, Logik, die das Framework ohnehin übernimmt, Redirects, die für ein altes Setup beibehalten wurden, Response-Metadaten, die niemand braucht, und Konfiguration, die nichts mehr bewirkt. Die meisten vorgeschlagenen Fixes sind Löschungen; einer ist eine einzelne Konfigurationszeile. Der Durchlauf listete auch die False Positives auf, die er verworfen hat, und das ist bei einem MCP-Endpunkt eine lange Liste von Dingen, die die Spezifikation verlangt.

Keiner dieser sechs war behoben, als der Lauf endete, also beschreibe ich sie nur der Art nach. Der Befund, den ich benennen kann, war am selben Vormittag behoben, und er war kein Sicherheitsproblem. Ein Pfad-Rewrite, der nackte URLs auf die Standardsprache schicken sollte, erfasste auch zwei Dateien, die im Wurzelverzeichnis der Website liegen müssen: die Verifizierungsdatei der Google Search Console und den IndexNow-Schlüssel. Beide lieferten in Production 404, also wären die erneute Verifizierung in der Search Console und die Validierung des IndexNow-Schlüssels gescheitert, und zwar unbemerkt.

Anthropics Beitrag erwähnt diesen Nebeneffekt nicht. Ein Durchlauf, der beweisen muss, was erreichbar ist, hält am Ende eine Karte des Servers in der Hand, und eine Karte zeigt fehlende Straßen so deutlich wie überzählige.

Durchlauf 2 der Attack Surface Reduction ohne Login: Wozu kann ein anonymer Request den Server bringen?

Diese Website hat nirgends ein Authentifizierungs-Gate, nichts, das ein Secret prüft oder einen Webhook annimmt. Also wurde aus Durchlauf 2 die Frage, die darunter liegt: Wozu kann ein anonymer Request den Server bringen? Er dauerte drei Minuten und kam mit vier Befunden zurück, alle mit derselben Form: ein Handler, der mehr Eingabe akzeptiert, als seine Aufgabe braucht. Keiner erreichte etwas Privates. Zwei davon ließen sich nur vollständig bestätigen, indem man den Nebeneffekt auslöst, also endeten ihre Prüfungen absichtlich am lokalen Build.

Warum fand Durchlauf 3 der Attack Surface Reduction auf einer Website ohne Kontrollen so wenig?

Auf dieser Website hat kein Optionspaar einen Schutz abgeschaltet, weil es fast nichts zum Abschalten gab. Ein Paar kann einen Schutz nur abschalten, wenn es Schutzmechanismen gibt, und eine Website ohne Auth und ohne Cookies gibt dem Durchlauf sehr wenig, woran er sich festbeißen kann. In zweieinviertel Minuten fand er eine bestätigte Inkonsistenz in den Metadaten, eine Lücke, deren Auswirkung er nicht bestätigen konnte, und einen latenten Fall.

Der dritte Durchlauf ist für Dinge gedacht, die Kontrollen zum Abschalten haben: einen Reverse Proxy, einen SSH-Daemon, die Zugriffsregeln eines VPN. Die Hostname-Deny-Regel und der Fall mit den Client-Zertifikaten in Anthropics Beitrag sind genau diese Art Ziel.

Die vierte Frage der Attack Surface Reduction: Was veröffentlicht das Deployment, ohne dass der Code es je referenziert?

Das schlimmste Leck, das ich diesen Monat gefunden habe, hatte einwandfreien Code. Es steckte in einer statischen Website, die ich deploye, in zwei Einstellungen, die jede für sich vernünftig waren. Die Website hatte keinen Build-Schritt, den reines HTML auch nicht braucht, also lieferte die Hosting-Plattform das Wurzelverzeichnis des Repositorys als Website aus. Und die Agenten, die ich für diese Website laufen lasse, legen ihre Arbeitsnotizen im selben Repository ab, das privat ist. Zusammen machte das interne Dateien unter erratbaren URLs erreichbar, und das blieb monatelang so. Ein Deploy-Review hat den Widerspruch zwischen beiden aufgedeckt. Der Fix war eine Allowlist dessen, was deployt wird, und danach eine Prüfung von außen, dass jeder interne Pfad 404 liefert.

Der Form nach ist das ein Befund für Durchlauf 3, ein Optionspaar, das stillschweigend einen Schutz fallen lässt, nur war der Schutz „dieses Repository ist privat“. Meine drei Durchläufe haben ihre Inventare aus dem Code gebaut, und ein Durchlauf, der aus dem Code inventarisiert, kann nur finden, was der Code benennt. Die vierte Frage inventarisiert aus dem Repository und fragt den laufenden Build, welche dieser Dateien er ausliefert. Dafür braucht es überhaupt kein Modell. Frag gegen den lokalen Production-Build jede getrackte Datei unter ihrem eigenen Pfad ab:

shell
git ls-files -z | grep -zv '^public/' | while IFS= read -r -d '' f; do
  code=$(curl -gs -o /dev/null -w '%{http_code}' "http://127.0.0.1:3130/$f")
  echo "$code $f"
done > probe.txt
cut -d' ' -f1 probe.txt | sort | uniq -c   # status counts
grep -v '^404' probe.txt                   # everything that did not 404

Das -g ist wichtig: Ohne es behandelt curl die eckigen Klammern im Namen eines Next.js-Routenordners als Glob und überspringt die Datei stillschweigend, was mein erster Lauf dieser Schleife bei 34 Dateien getan hat. Dann machst du dasselbe für den Public-Ordner, ohne dessen Präfix (Next liefert public/x.png unter /x.png aus), und markierst jede Datei, auf die keine Quelldatei verweist. Ein 200 ist nur ein Hinweis: Vergleiche den Body mit der Datei, bevor du sie als ausgeliefert bezeichnest.

Auf dieser Website dauerte die korrigierte Schleife sieben Sekunden. Von 679 getrackten Dateien außerhalb des Public-Ordners lieferte keine 200. Von 345 Dateien im Public-Ordner sind vier absichtlich gesperrt, sechs Bilder in alten Artikelordnern werden von keiner Quelldatei referenziert, 89 werden referenziert, und 246 waren Font-Slices, die meine Referenzprüfung übersehen hat, weil das Stylesheet, das sie benennt, selbst im Public-Ordner liegt. Das grep ist eine Heuristik; das curl ist der Beleg.

Der zweite Lauf zeigte auch etwas Neues. Siebzehn Requests bekamen einen Serverfehler, wo ein 404 hingehört hätte. Ausgeliefert wurde nichts, aber eine Änderung an der Erreichbarkeit vom selben Tag hatte diese Pfade geöffnet, und das spricht dafür, die Durchläufe nach jedem Eingriff erneut laufen zu lassen, nicht nur davor.

Next liefert das Wurzelverzeichnis des Repositorys nicht als Ordner aus: Es liefert seine Routen, seine Build-Assets und den Public-Ordner, und was die Routen zurückgeben, entscheidet der Code. Die Website, bei der es schiefging, hatte gar kein Framework. Die Prüfung kostet Sekunden, und nichts in einem rein statischen Deployment wird dich je dazu bringen, sie auszuführen.

Attack Surface Reduction vs. Bug-Hunting: Warum ist es besser, den Pfad zu schließen, als den Bug zu finden?

Ich halte das Entfernen erreichbaren Codes für den korrekteren Fix als das Finden des Bugs darin. Ein gefundener Bug ergibt einen Fix für genau einen Fehler, und der Code, in dem er steckte, bleibt für den nächsten erreichbar. Ein geschlossener Pfad nimmt jeden künftigen Fehler in diesem Code mit, auch die, die nie jemand melden wird. Im Fall OpenSSH musste niemand einen Speicherfehler im ML-DSA-Parser finden, damit sich der Fix lohnte.

Anthropics Variante setzt meist Gates, statt zu löschen, und zwischen beidem neige ich zum Löschen, überall dort, wo der Standard die einzige Konfiguration ist, die jemand betreibt. Ein Gate ist eine Prüfung, und eine Prüfung greift nur auf den Pfaden, die sie abdeckt: Das Gate in 10.5 sah sich den angekündigten Algorithmus an, während der Parser dem Key-Blob vertraute, und der Code dahinter blieb nur eine Abweichung davon entfernt, erreicht zu werden. Gelöschter Code hat keinen zweiten Weg hinein. Der Preis ist Optionalität. Wenn jemand den experimentellen Pfad zurückwill, kommt er über die Versionskontrolle zurück, nicht über ein Flag. Gates würde ich also weiterhin dort setzen, wo jemand ein Nicht-Standard-Setup betreibt, und das ist genau der Fall, den Anthropic einem Menschen zur Entscheidung überlässt.

Löschen verändert auch das Gespräch mit dem, der die Änderung reviewt. Ein Bericht, der sagt „hier ist ein Bug“, verlangt von ihm, den Bug zu verifizieren. Ein Patch, der sagt „dieser Code ist in deiner Standardkonfiguration unerreichbar, und deine Testsuite liefert dieselben Ergebnisse“, gibt ihm die Änderung und ihren Beleg zusammen.

Mauern sind ein anderes Werkzeug für eine andere Frage: Eine Sandbox wie srt begrenzt, was ein Prozess anfassen kann, während diese Methode von vornherein verkleinert, was ein Außenstehender erreichen kann. Und bei mehreren der Ausbrüche, die ich mir angesehen habe, war der Weg nach draußen nie Code, sondern ein Dienst oder eine Zugangsberechtigung, die der Agent bekommen hatte, oder hier ein Repository, das einem Webserver komplett übergeben wurde.

Solltest du Attack Surface Reduction gegen einen Live-Dienst oder einen lokalen Build laufen lassen?

Wenn du das morgen ausprobierst, lass die Durchläufe gegen einen lokalen Production-Build laufen, nicht gegen deinen Live-Dienst. Ein Scan deiner eigenen Production sieht genau wie ein Angriff aus. Als ich diese Woche Live-Websites auf geleakte Pfade geprüft habe, hat der Bot-Schutz der Plattform die Requests hinter eine Challenge gesetzt, und der Uptime-Monitor meldete die Website als down, bis sie aufgehoben war. Und manche Befunde lassen sich nur bestätigen, indem man genau das tut, wovor sie warnen, und das willst du nicht in Production tun.

Ein lokaler Build reproduziert, was die Anwendung tut, ohne Production anzufassen. Er reproduziert nicht das Caching des Hosts, und er isoliert ausgehende Aufrufe nicht von selbst, also sorg dafür, dass kein Durchlauf etwas auslöst, das den Rechner verlässt. Nimm Production für die ein, zwei Requests, die bestätigen, dass ein Befund live ist, und behebe ihn dann, bevor du darüber schreibst.

01 / Diskussion

Hier gibt es keine Kommentarspalte. Diskussionen laufen auf X.

Max Nardit@mnardit

02 / Weitere Artikel