I årtier har statisk applikationssikkerhedstest (SAST) været en af de mest effektive måder, hvorpå sikkerhedsteams kan skalere kodegennemgangen.
Men da vi byggede Codex Security, traf vi et bevidst designvalg: Vi startede ikke med at importere en statisk analysereport og bede agenten om at triagere den. Vi designede systemet til at starte med selve lageret—dets arkitektur, tillidsgrænser og tilsigtede adfærd—og til at validere det, det finder, før det beder en person om at bruge tid på det.
Årsagen er simpel: de sværeste sårbarheder er som regel ikke dataflow-problemer. De opstår, når kode tilsyneladende håndhæver et sikkerhedstjek, men det tjek faktisk ikke garanterer den egenskab, som systemet er afhængigt af. Med andre ord er udfordringen ikke kun at spore, hvordan data bevæger sig gennem et program – det er at afgøre, om forsvaret i koden virkelig fungerer.
SAST bliver ofte præsenteret som en klar pipeline: identificer en kilde til upålidelige input, spor data gennem programmet, og marker tilfælde, hvor disse data når en følsom destination uden at blive gennemgået. Det er en elegant model, og den dækker mange reelle fejl.
I praksis er SAST nødt til at foretage tilnærmelser for at forblive håndterbar i stor skala. Især i virkelige kodebaser med indirekte anvendelse, dynamisk dispatch, callbacks, refleksion og framework-tung kontrolflow. Disse tilnærmelser er ikke et angreb på SAST; det er realiteten ved at forsøge at ræsonnere om kode uden at udføre den.
Det er i sig selv ikke grunden til, at Codex Sikkerhed starter med en SAST-rapport.
Det dybere problem er, hvad der sker, efter du med succes sporer en kilde til et problem.
Selv når statisk analyse korrekt sporer input på tværs af flere funktioner og lag, skal den stadig besvare det spørgsmål, der faktisk afgør, om der findes en sårbarhed:
Tag et almindeligt mønster: kode kalder noget i retning af sanitize_html() før gengivelse af upålideligt indhold. En statisk analysator kan se, at saniteringen blev kørt. Det, den normalt ikke kan afgøre, er, om den sanitering rent faktisk er tilstrækkelig for den specifikke renderingskontekst, skabelonmotor, kodningsadfærd og de efterfølgende transformationer, der er involveret.
Det er her, det bliver vanskeligt. Problemet er ikke kun, om data når en modtager. Det handler om, hvorvidt kontrollerne i koden faktisk begrænser værdien på den måde, som systemet antager.
Med andre ord: der er stor forskel på “koden kalder en saniteringsfunktion” og “systemet er sikkert.”
Her er et mønster, der dukker op i virkelige systemer hele tiden.
En webapplikation modtager en JSON-payload, udtrækker en redirect_url, validerer den mod en tilladelsesliste-regex, URL-afkoder den og sender resultatet til en omdirigeringshandler.
En klassisk kilde-til-modtager-rapport kan beskrive strømmen:
upålidelig input → regex-kontrol → URL-afkodning → omdirigering
Men det egentlige spørgsmål er ikke, om kontrollen findes. Det er, om den kontrol stadig begrænser værdien efter de transformationer, der følger.
Hvis regexen kører før afkodning, begrænser den så faktisk den afkodede URL på den måde, som redirect-handleren fortolker den?
At besvare det betyder, at man skal ræsonnering om hele transformationskæden: hvad regexen tillader, hvordan afkodning og normalisering opfører sig, hvordan URL-parsing håndterer edge cases, og hvordan omdirigeringslogikken løser skemaer og autoriteter.
Mange af de sårbarheder, der er relevante i praksis, ser sådan ud: fejl i rækkefølgen af operationer, delvis normalisering, tvetydigheder ved parsing og uoverensstemmelser mellem validering og fortolkning. Dataflowet er synligt. Svagheden ligger i, hvordan begrænsninger forplanter sig – eller ikke forplanter sig – gennem transformationskæden.
Det handler ikke kun om et teoretisk mønster. I CVE-2024-29041(åbner i et nyt vindue) blev Express påvirket af et problem med åben omdirigering, hvor misdannede URL'er kunne omgå almindelige implementeringer af tilladelseslister på grund af den måde, omdirigeringsmål blev kodet og derefter fortolket på. Dataflowet var ligetil. Det sværere spørgsmål – og det, der afgjorde, om fejlen eksisterede – var, om valideringen stadig gjaldt efter transformationskæden.
Codex Security er bygget op omkring et simpelt mål: at reducere triage-byrden ved at afdække problemer med stærkere dokumentation. I produktet betyder det at bruge repo-specifik kontekst (inklusive en trussel model) og validere high-signal-problemer i et isoleret miljø, før de præsenteres.
Når Codex Security støder på en grænse, der ligner “validering” eller “sanitering”, betragter det ikke dette som blot en formalitet. Den forsøger at forstå, hvad koden forsøger at garantere, og derefter forsøger den at forfalske denne garanti.
I praksis har det en tendens til at se ud som en blanding af:
- Læsning af den relevante kodevej med fuld lagerkontekst, som en sikkerhedsforsker ville gøre, og søgning efter uoverensstemmelser mellem hensigt og implementering. Dette inkluderer kommentarer, men modellen stoler ikke nødvendigvis på kommentarer, så at tilføje //Halvar siger: dette er ikke en fejl over din kode forvirrer den ikke, hvis der virkelig er en fejl.
- At reducere problemet til den mindste testbare del (for eksempel transformationspipelinen omkring et enkelt input), så du kan ræsonnere om det uden at resten af systemet står i vejen. I den forstand udtrækker Codex Security små kodeudsnit og skriver derefter mikro-fuzzere til dem.
- Ræsonnering om begrænsninger på tværs af transformationer, i stedet for at behandle hver kontrol uafhængigt. Hvor det er relevant, kan dette omfatte formalisering som et tilfredsstillelighedsspørgsmål. Med andre ord giver vi modellen adgang til et Python-miljø med z3-solver, og den er god til at bruge det, når der er behov for det, ligesom et menneske ville være nødt til det, når man besvarer et særligt kompliceret inputbegrænsningsproblem. Dette er særligt nyttigt til at se på heltalsoverløb eller lignende fejl på ikke-standard arkitekturer.
- Udfører hypoteser i et sandbox-valideringsmiljø, når det er muligt, for at skelne "dette kunne være et problem" fra "dette er et problem". Der findes intet bedre bevis end en fuld end-to-end PoC med koden kompileret i debug-tilstand.
Dette er det centrale skift: i stedet for at stoppe ved “der findes en kontrol,” skubber systemet mod “invarianten holder (eller gør den ikke), og her er beviset”. Og modellen vælger det bedste værktøj til opgaven.
En rimelig reaktion er: hvorfor ikke gøre begge dele? Start med en SAST-rapport, og brug derefter agenten til at ræsonnere dybere.
Der er tilfælde, hvor forudberegnede fund er nyttige—særligt for snævre, kendte fejlklasser. Men for en agent, der er designet til at opdage og validere sårbarheder i kontekst, skaber det at starte med en SAST-rapport tre forudsigelige fejltilstande.
For det første kan det fremme en for tidlig indsnævring. En liste over fund er et kort over, hvor et værktøj allerede har kigget. Hvis du behandler det som udgangspunkt, kan du risikere at skævvride systemet til at bruge uforholdsmæssigt meget indsats i de samme områder, anvende de samme abstraktioner og overse problemklasser, der ikke passer ind i værktøjets verdenssyn.
For det andet kan det introducere implicitte vurderinger, som er svære at afvikle. Mange SAST-resultater indeholder antagelser om sanering, validering eller tillidsgrænser. Hvis de antagelser er forkerte—eller bare ufuldstændige—kan det at føre dem ind i ræsonnerings-loopet flytte agenten fra “undersøg” til “bekræft eller afvis,” hvilket ikke er det, vi ønsker, at agenten skal gøre.
For det tredje kan det gøre det sværere at evaluere ræsonneringssystemet. Hvis pipelinen starter med SAST-output, bliver det svært at adskille, hvad agenten har opdaget gennem sin egen analyse, fra hvad den har arvet fra et andet værktøj. Den adskillelse er vigtig, hvis du vil måle systemets kapaciteter præcist, hvilket er nødvendigt, for at systemet kan forbedres over tid.
Derfor byggede vi Codex Security til at starte der, hvor sikkerhedsforskning begynder: med koden og systemets hensigt, og med validering brugt til at hæve tillidsniveauet, før vi afbryder en person.
SAST-værktøjer kan være fremragende til det, de er designet til: at håndhæve sikker kodningsstandarder, at identificere ligetil source-to-sink-problemer og at opdage kendte mønstre i stor skala med forudsigelige afvejninger. De kan være en vigtig del af et forsvar i flere lag.
Dette indlæg er mere fokuseret: det handler om, hvorfor en agent, der er designet til at analysere adfærd og validere resultater, ikke bør starte sit arbejde med at være bundet til en statisk liste over resultater.
Det er også værd at fremhæve en relateret begrænsning ved ren source-to-sink-tænkning: ikke alle sårbarheder er et dataflow-problem. Mange reelle fejl er problemer med tilstand og invarians—omgåelse af arbejdsgange, huller i autorisation og fejl af typen “systemet er i den forkerte tilstand”. For disse typer fejl når en kontamineret værdi ikke frem til et enkelt “farligt afløb.” Risikoen ligger i det, programmet antager altid vil være sandt.
Vi forventer, at sikkerhedsværktøjsøkosystemet fortsætter med at blive forbedret: statisk analyse, fuzzing, runtime-beskyttelse og agentbaserede arbejdsgange vil alle spille en rolle.
Det, vi vil have Codex Security til at være god til, er den del, der koster sikkerhedsteams mest: at omsætte “det her ser mistænkeligt ud” til “det her er reelt, her er hvordan det fejler, og her er en rettelse, der matcher systemets hensigt.”
Hvis du vil vide mere om, hvordan Codex Security scanner repositories, validerer fund og foreslår rettelser, kan du se vores dokumentation(åbner i et nyt vindue).


