
Audit von Googles zx mit und ohne Review-Skill
Der Skill Bench, Teil 4 von 4. Gleiches Modell, gleicher Prompt, ein Skill installiert oder nicht. Ebenfalls in dieser Reihe: eine Landing Page, ein Telegram-Bot und das Debuggen eines Snake-Spiels.
Nach drei Einträgen in dieser Reihe war das Muster konsistent: Der Skill-Ansatz leistet mehr, prüft mehr, verbraucht mehr Tokens und liefert ein durchdachteres Ergebnis. Dieser Eintrag durchbricht dieses Muster. Es ist das einzige Mal im gesamten Bench, dass der Skill-Durchlauf günstiger war als die Baseline, und es ist auch das einzige Mal, dass der Skill-Ansatz das größte Einzelergebnis der Reihe verpasst hat. Beide Aussagen treffen gleichzeitig zu, und die Spannung zwischen ihnen ist das nützlichste Ergebnis, das wir aus diesem Projekt gewonnen haben.
Warum Googles zx
Wir suchten eine Code-Audit-Aufgabe mit drei Eigenschaften: echter Code, kein künstlich mit Fehlern versehenes Snippet; etwas, das ein Entwickler mittleren Niveaus plausibel an einem Dienstag zur Überprüfung erhalten könnte; und eine Codebasis, die bekannt genug ist, damit Leser unsere Behauptungen anhand der tatsächlichen Quelle überprüfen können, anstatt uns blind zu vertrauen.
google/zx erfüllte alle drei Kriterien. Es ist Googles Bibliothek zum Schreiben von Shell-Skripten in JavaScript, populär genug, dass ein signifikanter Teil der Node-Tooling davon abhängt, und klein genug, dass ein Audit einer einzelnen Datei eine faire Aufgabe und kein Forschungsprojekt ist. Wir wählten src/core.ts, die Datei, die die eigentliche Prozess-Erzeugung und Umgebungsbehandlung vornimmt, frisch aus dem Repository. Hier gibt es keine konstruierte Schwachstelle. Es ist eine echte, aktiv gepflegte Datei, und zx ist im Allgemeinen gut aufgebaut: saubere Struktur, sinnvolle Standardwerte an den meisten Stellen, die Art von Code, die eine oberflächliche Lektüre besteht. Das ist genau das Szenario, in dem ein Audit seinen Wert beweist, indem es die eine Sache findet, die eine oberflächliche Lektüre übersieht, oder eben nicht.
Methodik
Zwei Durchläufe, gleiches Modell, gleiche Anweisung: Prüfen Sie src/core.ts von google/zx und erstellen Sie Ergebnisse, die von P0 bis P3 eingestuft sind, jeweils mit Ort, was kaputtgeht, wann es kaputtgeht und einem minimalen Fix. Durchlauf eins erhielt diese Anweisung und nichts weiter. Durchlauf zwei erhielt die identische Anweisung plus unsere eigene Sicherheits- und Code-Review-Checkliste, die in unserem Security Pack und Developer Toolkit enthalten ist und vor Beginn des Audits vollständig gelesen wurde.
Gleicher Vorbehalt wie bei jedem anderen Eintrag in dieser Reihe: Dies ist ein Durchlauf pro Ansatz, ein Modell, eine Datei. Wir behaupten nicht, dass sich die spezifischen Ergebnisanzahlen bei einem erneuten Durchlauf replizieren lassen. Wir berichten, was passiert ist, mit echter Telemetrie und einem Muster in der Art der Dinge, die jeder Ansatz erfasst, das unserer Meinung nach besser verallgemeinerbar ist als die reinen Zahlen.
Was die Baseline fand
Alleingelassen las das Modell core.ts und zog aus eigener Initiative auch util.ts und error.ts zur Kontextualisierung heran, bevor es etwas aufschrieb. Niemand hatte es dazu angewiesen. Es entschied, dass die Datei isoliert keinen Sinn ergab, und suchte in ihren Nachbardateien, was sich als relevant erwies.
Das Top-Ergebnis der Baseline und das Ergebnis mit der höchsten Schweregrad des gesamten Bench ist dieses hier. In Zeile 139 setzt core.ts seine Umgebungseinstellung standardmäßig auf env: process.env. Das ist keine Kopie der Umgebung, sondern eine Live-Referenz darauf. Sobald man das weiß, ist die Konsequenz offensichtlich: Wenn ein Codepfad etwas wie $.env.FOO = 'x' tut, setzt er keine Variable, die auf diesen einen Shell-Aufruf beschränkt ist. Es mutiert process.env für die gesamte laufende Anwendung, was bedeutet, dass jeder andere Teil des Programms, jede andere Bibliothek, alles, was Umgebungsvariablen danach liest, die Änderung sieht. Eine Konfigurationsanpassung, die für einen Unterprozessaufruf gedacht war, sickert in den globalen Zustand. In einem langlebigen Serverprozess oder in jedem Skript, das mehrere zx-Aufrufe mit leicht unterschiedlichen Umgebungen verteilt, ist das die Art von Fehler, die in einem schnellen Test nicht auftaucht und dann Tage später einen völlig unabhängigen Teil des Systems beschädigt. Wir haben dies direkt anhand der Quelle überprüft, anstatt dem Wort des Modells zu vertrauen, und die Zeile tut genau das, was das Ergebnis besagt.
Der Rest der Baseline-Liste, bewertet mit P2 und P3, war solide, ohne spektakulär zu sein: ein Bash-Erkennungsfehler, der stillschweigend verschluckt wird und später als irreführende, nicht zusammenhängende Fehlermeldung anstelle der eigentlichen Ursache auftaucht, und ein Fall, in dem break() synchron aus einem .catch()-Handler geworfen wird, was die Art von Kontrollflussfehler ist, der leicht zu schreiben und ärgerlich zu debuggen ist, weil der Stack-Trace auf eine unbrauchbare Stelle zeigt.
Gesamtergebnis Baseline: ein P1, zwei P2s, vier P3s.
KOSTENLOSES STARTER-PAKET
Neugierig, was ein ungeführtes Claude-Audit in Ihrem eigenen Code findet, bevor Sie eine Checkliste hinzufügen? Unser kostenloses Starter-Paket ist ein schneller Weg, einen zweiten Durchlauf zu starten.
Holen Sie sich das kostenlose Starter-PaketWas der Checklisten-Ansatz fand
Der Skill-geführte Durchlauf folgte unserer Code-Review-Checkliste, derselben, die in unserer Übersicht der Sicherheits-Skills behandelt wird, und es las sich wie ein völlig anderer Prüfer: gleiche Datei, gleicher Zugriff, ein völlig anderer Satz von Bedenken kam zum Vorschein.
Sein bestes Ergebnis war eine unbehandelte Promise-Ablehnung: Aufrufstellen für break() und timeout() rufen kill() auf, ohne darauf zu warten, sodass eine Ablehnung von diesem Aufruf nirgendwo landen kann und den Prozess außerhalb eines vom Aufrufer geschriebenen try/catch zum Absturz bringen kann. Es fand auch einen TypeError, der auftritt, wenn etwas versucht, eine ProcessPromise asynchron zu iterieren, nachdem sie bereits angehalten wurde – ein echter Grenzfall, der nur unter einer spezifischen Abfolge von Aufrufen auftritt. Und es markierte, dass ZX_PREFIX und ZX_POSTFIX ohne Bereinigung direkt in jeden Shell-Aufruf eingefügt werden, was die Aufmerksamkeit eines Maintainers wert ist, wenn einer der Werte jemals von außerhalb des vertrauenswürdigen Skriptautors stammen kann.
Dies sind echte, gut formulierte Ergebnisse, keine Füllmaterial. Der Bericht des Checklisten-Ansatzes war auch das nutzbarere der beiden Dokumente in seinen eigenen Bedingungen: einheitliche Struktur, konsistente Schweregrad-Sprache, jeder Eintrag folgte dem gleichen Format von Ort-Auswirkung-Fix, ohne dass das Modell dieses Format spontan erfinden musste.
Gesamtergebnis Checkliste: zwei P2s, fünf P3s. Keine P1s, und bemerkenswerterweise überhaupt kein process.env-Ergebnis.
Die Überschneidung und wie gering sie war
Vergleicht man beide Listen, ist die Überschneidung nahezu null. Sechs Baseline-Ergebnisse, sieben Checklisten-Ergebnisse, insgesamt dreizehn, und keines davon nennt die gleiche Grundursache. Die process.env-Mutation. Das Verschlucken der Bash-Erkennung. Der synchrone Wurf in einem Catch. Das nicht-erwartete kill(). Der TypeError des angehaltenen Iterators. Das unsanierte Prefix/Postfix-Splicing. Jeder einzelne ist ein anderer Codepfad.
Das ist eine größere Überraschung als jede einzelne Liste. Zwei kompetente Prüfer, die sich die gleichen etwa 300 Zeilen TypeScript ansehen, einer geführt von einer strukturierten Checkliste und einer nicht, und sie landen auf fast völlig unterschiedlichen Problembereichen. Hätten Sie uns im Vorfeld gesagt, dass der Checklisten-Durchlauf die Baseline-Liste im Wesentlichen noch einmal überprüfen und verfeinern würde, hätten wir es geglaubt. Das ist nicht passiert. Die Checkliste verfeinerte nicht dieselbe Suche, sie führte eine andere Suche durch.
Die Zahlen
| Baseline (no skill) | Skill arm (code-review checklist) | Delta | |
|---|---|---|---|
| Verwendete Tokens | 87,899 | 81,743 | −7% |
| P1-Ergebnisse | 1 | 0 | −1 |
| P2-Ergebnisse | 2 | 2 | 0 |
| P3-Ergebnisse | 4 | 5 | +1 |
| Gesamtergebnisse | 7 | 7 | 0 |
| Proaktives Lesen benachbarter Dateien | Ja (util.ts, error.ts) | Nein | — |
| Ergebnis höchster Schweregrad | process.env-Mutation (verifiziert) | — | — |
Jeder andere Eintrag in dieser Reihe zeigte, dass der Skill-Ansatz mehr Tokens für ein disziplinierteres Ergebnis kostete. Dies ist die einzige Ausnahme: Der Checklisten-Ansatz war 7% günstiger. Unsere Interpretation ist, dass eine Checkliste den Suchraum eingrenzt, und ein engerer Suchraum ist kostengünstiger auszuführen, selbst wenn er auch einige der Pfade abschneidet, die ein freilaufender Durchlauf erkundet hätte.
Untergrenze vs. Obergrenze
Dies ist die schärfste Erkenntnis, die wir aus allen vier Einträgen gewonnen haben, und sie zeigt sich hier am deutlichsten. Die Checkliste machte das Audit günstiger und verlieh ihm ein rigoroseres, konsistenteres Format. Was sie nicht tat, war, den process.env-Fehler zu finden, da dieses Ergebnis keiner Kategorie der Checkliste entstammte. Es kam daher, dass die Baseline bemerkte, dass core.ts allein schwer zu beurteilen war, aus eigener Initiative util.ts und error.ts hinzuzog und diesem Instinkt an einen Ort folgte, auf den die Struktur der Checkliste nie hingewiesen hatte.
Eine Checkliste hebt die Untergrenze an. Sie garantiert einen Mindeststandard der Abdeckung: Jede Kategorie wird geprüft, jedes Ergebnis wird auf die gleiche Weise dokumentiert, und Sie verlieren keinen einfachen Fang an einem schlechten Tag. Sie hebt die Obergrenze nicht an. Das bestmögliche Ergebnis in einer bestimmten Datei könnte außerhalb jeder Kategorie liegen, die die Checkliste aufzählt, und ein Prozess, der nur die Checkliste abarbeitet, wird selbstbewusst und in einem schön formatierten Bericht daran vorbeigehen.
Das ist kein Argument gegen Checklisten. Keines der sieben Ergebnisse der Checkliste war schlecht, und zwei davon waren die Art von Dingen, die ein beschäftigter menschlicher Prüfer unter Zeitdruck plausibel übersieht. Es ist ein Argument dafür, zu wissen, wofür eine Checkliste da ist. Sie ist ein Werkzeug zur Anhebung der Untergrenze, nicht zur Anhebung der Obergrenze, und sie als beides zu behandeln, führt dazu, dass ein echtes P1 eine ansonsten gründlich aussehende Überprüfung durchrutscht.
SKILLPROOF-PAKET
Die exakte Checkliste, die in diesem Test lief, diejenige, die das nicht-erwartete kill() und das unsanierte Prefix-Splicing fand, ist in unserem Security Pack zusammen mit dem Rest unserer am besten bewerteten Review-Skills enthalten.
Holen Sie sich das Security Pack — $10So führen Sie selbst ein Zwei-Phasen-Audit durch
Angesichts unserer Ergebnisse ist unsere tatsächliche Empfehlung nicht „verwenden Sie eine Checkliste“ oder „überspringen Sie die Checkliste“. Es ist, beides auszuführen, bei allem, was wichtig ist.
Beginnen Sie mit einem freien Durchlauf. Richten Sie das Modell auf die Datei, geben Sie ihm die Audit-Anweisung und lassen Sie es lesen, was immer es sonst noch lesen möchte. Geben Sie ihm keine Bewertungsrichtlinie. Dies ist der Durchlauf, der die besten Chancen hat, das zu finden, woran niemand gedacht hat, es auf eine Liste zu setzen, weil er nicht auf die Liste beschränkt ist.
Führen Sie dann einen zweiten, separaten Durchlauf mit einer strukturierten Checkliste durch, unserer oder Ihrer eigenen. Dies ist der Durchlauf, der die Abdeckung garantiert: Die Kategorien, die manuell langweilig zu prüfen sind, aber leicht zu überspringen, wenn man einem Instinkt folgt – Bereinigung, Fehlerbehandlung, Ressourcenbereinigung – werden jedes Mal durchlaufen.
Vergleichen Sie die beiden Berichte, bevor Sie einen davon als endgültig betrachten. Wenn unsere Überschneidungszahl in Ihrem Code so Bestand hat wie bei zx, erwarten Sie, dass die beiden Listen weniger als die Hälfte ihrer Ergebnisse teilen. Betrachten Sie dies als erwartetes Ergebnis, nicht als Zeichen dafür, dass einer der Durchläufe fehlgeschlagen ist. Das vollständige Testprotokoll beschreibt detaillierter, wie wir diese Art von gepaartem Durchlauf strukturieren, einschließlich der Kontrolle, dass das Modell seine eigene frühere Ausgabe liest.
Wenn Sie nur Budget für einen Durchlauf haben, lautet unser ehrlicher Rat basierend auf diesem Ergebnis: Führen Sie zuerst den freien Durchlauf durch. Es ist derjenige, der mit größerer Wahrscheinlichkeit das Ergebnis findet, nach dem Sie nicht wussten, dass Sie suchen sollten. Wenn es die Zeit erlaubt, folgen Sie ihm dann mit der Checkliste, um sicherzustellen, dass nichts Langweiliges übersehen wurde. Für einen umfassenderen Überblick, welche Skills diese Art von Überprüfung gut handhaben, sehen Sie sich unsere Übersicht der besten Coding-Skills an.
FAQ
Ist das process.env-Ergebnis eine echte Schwachstelle in zx?
Es ist ein echtes Verhalten, das die Aufmerksamkeit eines Maintainers wert ist, keine offengelegte CVE und nichts, was wir als aktiven Exploit darstellen. zx ist insgesamt eine gut gebaute, aktiv gepflegte Bibliothek, und dies ist eine Designentscheidung, eine Live-Referenz anstelle einer Kopie, die eine echte Mutationskonsequenz für jeden Codepfad hat, der in $.env schreibt. Wir haben die Zeile selbst anhand der Quelle überprüft, anstatt dem Bericht des Modells zu vertrauen, und genau deshalb bezeichnen wir es als das Top-Ergebnis des gesamten Bench.
Warum war der Skill-Ansatz hier günstiger, obwohl er überall sonst in dieser Reihe teurer war? Unsere beste Erklärung ist der Umfang. Ein Design-Skill im Landing-Page-Eintrag lädt zur Iteration ein: Ausgabe prüfen, überarbeiten, erneut prüfen. Eine Review-Checkliste funktioniert anders. Sie definiert einen festen Satz von Kategorien, die einmal durchlaufen werden, was die Suche eingrenzt, anstatt sie zu erweitern. Engere Suche, weniger Tokens. Es ist ein plausibler Mechanismus, kein bewiesener, da dies ein einzelner Durchlauf ist.
Sollte ich einem Checklisten-geführten KI-Code-Review vertrauen, alles zu finden? Nein, und das ist das Hauptergebnis hier. Eine Checkliste ist ein Werkzeug zur Anhebung der Untergrenze: Sie garantiert eine konsistente Mindestabdeckung über bekannte Kategorien hinweg. Sie ist kein Werkzeug zur Anhebung der Obergrenze, und das größte Ergebnis in diesem gesamten Bench kam von einem Durchlauf, der keiner folgte. Verwenden Sie eine Checkliste für Abdeckung und Konsistenz. Verwenden Sie sie nicht als einzigen Durchlauf für Code, der wirklich wichtig ist.
Was bedeutet das in der Praxis für die Wahl eines Claude Code Review Skills? Betrachten Sie „welcher Skill“ nicht als einzige Entscheidung. Betrachten Sie „wie viele Durchläufe“ als die wichtigere. Ein guter Checklisten-Skill, wie der in unserer code-review-checklist-Liste, ist es wert, für die Konsistenz und die Kategorien, die er garantiert, installiert zu werden. Kombinieren Sie ihn mit mindestens einem ungeleiteten Durchlauf bei allem, was Sie tatsächlich ausliefern würden, und lesen Sie unsere Sicherheits-Skills-Abdeckung, um zu erfahren, wie wir Review-Skills im Katalog gegeneinander abwägen.
Das ist die Reihe. Vier Aufgaben, vier ehrliche Urteile, und der rote Faden durch alle ist derselbe: Ein Skill ändert, was ein Modell prüft, nicht ob es zur Arbeit fähig ist. Ob dieser Kompromiss es wert ist, hängt ganz davon ab, was Sie bauen und wie genau es danach jemand betrachten wird.
★ 9.6/10 × 3
Das kostenlose Starterpaket
Die 3 Skills mit unseren besten Testergebnissen plus die Install-Checkliste — das Setup, das wir auf einen frischen Rechner packen würden. Kostenlos, per E-Mail.