TL;DR
Reasoning Models sind für die meisten SAST-Regeln nicht erforderlich, aber für Edge Cases wie Path Traversal in JavaScript fangen sie doppelt so viele False Positives ab.
Sind Reasoning Models nur Hype?
„Reasoning Models“ erleben gerade einen Aufschwung. Die großen KI-Labs befinden sich in einem Führungsstreit; sie verschieben die Grenzen von Modellgröße und -leistung durch Skalierungsgesetze, intelligenteres Vortraining und Feinabstimmung mit RLHF (Reinforcement Learning from Human Feedback). Sie schichten auch Chain-of-Thought-Prompting auf, um Modelle während der Inferenz „laut denken“ zu lassen. Dies ermöglicht es ihnen, Nicht-KI-Systeme bei Logikaufgaben zu dominieren – und dabei die Bestenlisten anzuführen.
Das ist beeindruckend. Aber sind sie in der Praxis wirklich nützlich? Das hängt davon ab.
Im Fall von AutoTriage* hängt viel von der Komplexität der SAST**-Regel ab.
*Kurze Zusammenfassung – AutoTriage ist eine Funktion, die Aikido verwendet, um False-Positive-SAST-Findings herauszufiltern.
**Ein SAST-Finding ist eine potenzielle Schwachstelle, die im Quellcode entdeckt wurde, wie von einem fest codierten Musterdetektor gemeldet.
Zu aufwendig für die meisten SAST-Regeln
AutoTriage funktioniert in zwei Schritten: Zuerst versuchen wir, die Möglichkeit der Ausnutzbarkeit auszuschließen. Ist dies möglich, können wir einen False Positive herausfiltern. Dies erfordert ein Schwarz-Weiß-Denken bezüglich der Erreichbarkeit Benutzergesteuerter Variablen in Schwachstellen. Das Modell prüft im Wesentlichen, ob die Variable tatsächlich Benutzergesteuert ist und ob eine Sanitisierung/Validierung/Casting vorhanden ist. Und wenn es eine Form der Mitigation gibt, wird geprüft, ob diese tatsächlich wirksam ist.
Der zweite Schritt erfolgt nur, wenn wir die Möglichkeit der Ausnutzbarkeit im ersten Schritt nicht ausschließen können. Wir konzentrieren uns dann auf die Priorisierung. Die Priorität wird durch die Wahrscheinlichkeit, dass etwas schiefgehen könnte, und den Schweregrad, falls es schiefgehen sollte, definiert. Dieser zweite Schritt ist weniger Schwarz-Weiß, hängt aber auch von subjektiven Schätzungen ab – zum Beispiel, wenn eine Variable als Benutzergesteuert angesehen wird, obwohl uns der vollständige Kontext fehlt.
Für die meisten Regeln können wir zusammenfassen, wie dies mit einer angemessenen Anzahl von „Faustregeln“ zu bewerkstelligen ist, wodurch Reasoning Models überflüssig werden: Sie weisen tendenziell eine ähnliche Genauigkeit auf, sind aber mit einem deutlich höheren Preis verbunden.
Warum kleine Reasoning Models funktionieren
Einige Regeln sind überraschend komplex, und nicht-schlussfolgernde Modelle haben Schwierigkeiten, sie zu erfassen. Stellen Sie sich vor, Sie würden für jedes Wort, das Sie sagen, genau denselben mentalen Raum nutzen: Zuerst fragt Sie jemand: „Was ist 1+1?“ Dann fragt dieselbe Person: „Was ist 26248 + 346237?“ Während normale Modelle mit unterschiedlichen Komplexitätsgraden zu kämpfen haben, können Reasoning-Modelle diese bewältigen, indem sie für komplexe Eingaben einfach mehr Worte verwenden und größere Probleme in kleinere, besser handhabbare Teilprobleme zerlegen.
Leider sind sie, da sie mehr Tokens verbrauchen, im Allgemeinen auch teurer. Modelle, die als Reasoning-Modelle strukturiert sind, leiden jedoch weniger unter der Verkleinerung des Modells als nicht-schlussfolgernde Modelle. Es gibt zwei Gründe, größere Modelle zu verwenden: (1) Sie haben mehr Kapazität, um mehr Wissen zu speichern (wobei viel Wissen im Fall der Triage von Schwachstellen nicht wirklich notwendig ist). (2) Größere Modelle sind pro Wort tendenziell etwas genauer. Reasoning-Modelle können sich jedoch dank ihrer Reasoning-Struktur von Fehlern erholen. Trotz des höheren Token-Verbrauchs ist es daher in der Praxis machbar, mit kleineren Modellen mit geringeren Kosten pro Token zu arbeiten, um den höheren Token-Verbrauch auszugleichen.
Path Traversal in Javascript
Path Traversal ist eine Regel, bei der Reasoning-Modelle wirklich glänzen können, da sie in der Triage überraschend komplex sind. Path Traversal ist eine Schwachstelle, bei der EndBenutzer Dateien außerhalb eines vorgesehenen Verzeichnisses lesen oder schreiben könnten. Stellen Sie sich zum Beispiel vor, Google Drive hätte für jeden Benutzer einen separaten Ordner in einem Dateisystem wie diesem:
Google Drive/userId1/
Google Drive/userId2/…Wenn Sie das nächste Mal eine Ihrer Dateien herunterladen möchten, senden Sie eine GET-Anfrage von Ihrem Browser-Client an Google Drive, z. B. mit dem Dateinamen myDogEatingShoes.jpg. Wenn diese Datei existiert, beginnt Ihr Download umgehend. Doch was wäre, wenn Sie den folgenden Dateinamen versuchen würden: ../userId2/mypasswords.txt. Hätte Google Drive sein Backend nicht vor Path Traversal geschützt, dann könnten Sie möglicherweise eine 'mypasswords.txt'-Datei von einem anderen Benutzer herunterladen, sofern diese Datei existiert.
Verschiedene Path Traversal Angriffe
Um Path Traversal SAST-Ergebnisse zu triagieren, müssen wir verschiedene Fälle verstehen, wann etwas anfällig ist oder nicht. Beginnen wir mit den einfachen Fällen und steigern wir die Komplexität schrittweise.
Muster 1: ‘../’
Das Hauptproblem hier ist das Muster ‘../’. Wenn Sie aus einem Dateipfad mit ‘../’ lesen oder in einen solchen schreiben, könnte dies dazu führen, dass das vorgesehene Verzeichnis verlassen wird und an einer nicht beabsichtigten Stelle gelesen/geschrieben wird. Wenn also keine Überprüfung auf ‘../’ im Dateipfad erfolgt und die Datei clientseitig angegeben wird, liegt eine echte Schwachstelle vor. In den wirklich schlimmen Fällen könnten Hacker Dateien mit Anmeldeinformationen auf Ihrem System lesen.
Muster 2: ‘..\\’
Stellen Sie sich vor, Sie haben auf ‘../’ geprüft, aber der Code läuft auf einem Windows-System. Sie hätten wieder ein Problem, da Path Traversal mit ‘..\\’-Mustern immer noch möglich ist. Soweit so gut, zwei Faustregeln zur Überprüfung sind doch noch überschaubar, oder?
Muster 3: ‘..’
Um schöne und saubere Pfade ohne fehlende Slashes zu erhalten, verwenden viele Leute Funktionen wie path.resolve() oder path.join(). Hier beginnt der Spaß. Stellen Sie sich so etwas vor:
if (userControlledSubPath.includes(‘../’) || userControlledSubPath.includes(‘..\\’)|| filename.includes(‘../’) || filename.includes(‘..\\’))
{
throw new Error(‘Path traversal attempt detected);
}
const filepath = path.join(HARDCODED_BASE_PATH, userControlledSubPath, filename);
return fs.readFileSync(filepath);Es stellt sich heraus, dass dies immer noch anfällig ist: Wenn ein Angreifer userControlledSubPath === '..', die path.join wird es immer noch als eine Verzeichnisebene höher gehend interpretieren.
Allerdings ist das letzte Argument in path.join() immun gegen diesen Angriff. Würde ein Angreifer „..“ im letzten Argument angeben, würde die path.join() Funktion ein Verzeichnis anstelle eines Dateipfads zurückgeben, was zu einem ungültigen Lese-/Schreibvorgang führen würde.
Muster 4: „/*“
In einem neuen Beispiel hatten wir wieder einen solchen Test:
if (filename.includes(‘..’))
{
throw new Error(‘Path traversal attempt detected);
}
const filepath = path.resolve(HARDCODED_BASE_PATH, filename);
return fs.readFileSync(filepath);Das sieht sicher aus, oder? Die Prüfung deckt die Fälle „..“, „../“ und „..\\“ ab – das ist elegant! Nun kommt die überraschende Art und Weise, wie dies immer noch anfällig ist. Trommelwirbel… trrrrrrrrr… Wenn ein Argument in path.resolve() mit einem Schrägstrich beginnt, ignoriert es alle vorherigen Argumente. Wenn ein Angreifer also etwas wie filename = /etc/passwd macht, dann path.resolve() wird den fest codierten Basispfad ignorieren und sich zu /etc/passwd. Beängstigend, oder? Wir hätten auch auf diesen nachgestellten Schrägstrich prüfen sollen. Beachten Sie, dass die Verwendung von path.join() hätte es sicher gemacht.
Die Komplexität würdigen
Charlie Chaplin sagte einmal: „Einfachheit ist keine einfache Sache.“ Dies trifft auch hier zu: Es gibt einfache, effektive Abhilfemaßnahmen, aber man muss zuerst die Bandbreite möglicher Angriffsvektoren verstehen. Die einfachste und robusteste Abhilfemaßnahme gegen Path Traversal besteht darin, den Pfad zuerst aufzulösen und zu prüfen, ob er immer noch mit dem beabsichtigten Basispfad beginnt. Es gibt keine Möglichkeit, diese Prüfung zu umgehen.
Allerdings hat das AutoTriage Team nicht den Luxus, Abhilfemaßnahmen wählen zu können. Wir müssen alternative Lösungen als sicher markieren können, damit wir Kunden nicht unnötig mit Fehlalarmen überfordern. Wir haben nun 4 verschiedene Angriffsvektoren für Path Traversal gesehen, und sie alle gehen mit spezifischen Prüfungen einher. Für jeden dieser Angriffsvektoren muss das LLM prüfen, ob er mit allen Anforderungen möglicherweise auftreten kann, um entweder einen erfolgreichen Angriff durchzuführen oder jede Möglichkeit eines Angriffs auszuschließen.
Obwohl Reasoning-Modelle nicht der Standard für die meisten Regeln sind, können sie für Path Traversal in JavaScript doppelt so viele Fehlalarme sicher herausfiltern wie Nicht-Reasoning-Modelle. Das ist ein Game Changer für die Rauschreduzierung.

