Produkt Anvendelse Priser Vejledninger Om os Log ind Start gratis
CodeControl · Teknisk dokumentation

Sådan virker CodeControl i virkeligheden

Det her er den lange udgave, skrevet til den, der bliver spurgt, om værktøjet dur — en udvikler, en bureauchef, en CTO eller den teknisk interesserede ejer, der står for vurderingen. Den dækker, hvad der bliver tjekket, hvor hver konklusion kommer fra, hvor dybt dækningen går pr. økosystem, og hvor grænserne går. Intet her er ønsketænkning; det beskriver det, der kører.

Leder du efter udgaven i almindeligt sprog? CodeControl forretningsmæssigt

01 · Scanningen

Hvad der sker mellem et push og et fund

En scanning opløser afhængighedssættet, beriger hver post, matcher den mod live-data og lander som én samlet observation, der forgrener sig til ét fund pr. berørt element. Fund er afledte, aldrig gemt to gange, og hver dimension lukker sig selv, når den er ryddet.

OPLØS
Native lockfile- og manifest-parsing, derefter fallbacks
Native parsere er autoritative — præcise versioner og en reel opdeling i direkte og transitive afhængigheder, hvor formatet udtrykker det. GitHubs dependency-graph-SBOM udfylder de økosystemer, parserne ikke dækker, Maven-parent-POM-opløsning genskaber de versioner, en POM arver frem for at angive, og et beregnet PyPI-træ udfylder de transitive, når et projekt kun har fastlåst sit direkte sæt.
BERIG
Afhængighedskæder og scope-klassificering
En gennemgang af grafen beregner den korteste kæde fra noget, projektet faktisk selv har erklæret — express › body-parser › qs — så hvert transitivt fund kan fortælle, hvordan pakken kom ind. Afhængigheder, der kun bruges under udvikling, identificeres ud fra det, manifesterne selv angiver, og rapporteres ét alvorlighedstrin lavere med begrundelsen i fundets tekst.
MATCH
Sikkerhedsadvarsler, udnyttelsesdata, registries, repository-indhold
OSV.dev for sårbarheder og ondsindede pakker; CISA KEV og FIRST EPSS for om nogen rent faktisk udnytter dem; otte pakke-registries plus endoflife.date for forældet, udløbet, uvedligeholdt og licens; oprettelsesdatoer fra registries for pakkers omdømme; og selve repository-indholdet for hemmeligheder, workflows, containere og typosquats.
UDSTED
Én samlet observation, ét fund pr. berørt element
Fund er nøglet pr. forekomst, ikke pr. repository. En udvikler, der opdaterer 28 ud af 31 pakker og ikke kan rette de sidste 3, skal kunne registrere præcis dét — et samlet fund bliver stående på grund af de 3, efterlader de 28 ubekræftede — eller lukker alle 31 på én gang, i samme øjeblik der kvitteres. Sikkerhedsadvarsler grupperes stadig pr. pakke, fordi ét versionsløft rydder alle CVE'er mod den samme artefakt.
02 · Kadence

Fire udløsere, fordi de svarer på hver sit spørgsmål

Næsten alt, hvad en scanning melder, ændrer sig kun, når koden ændrer sig — afhængigheder, licenser, hemmeligheder, base-images, pipeline-konfiguration. Udnyttelse er undtagelsen: en afhængighed kan komme i CISAs katalog over udnyttede sårbarheder i løbet af natten, uden at der er committet noget som helst. Den skævhed er grunden til, at planen er delt op i stedet for ensartet.

Fuld scanning · hver 14. dag

Alle dimensioner, fra bunden. Forskudt på tværs af mål, så de ikke alle går i gang på samme dato.

Nyt tjek af sikkerhedsadvarsler · hver nat

Sårbarheds- og udnyttelsesdata opdateres mod det kendte afhængighedssæt. Alt uden for sårbarhedsbilledet føres ordret videre fra forrige øjebliksbillede — ellers ville et delvist øjebliksbillede lukke hvert eneste fund om hemmeligheder og licenser som "rettet".

Push til hovedgrenen · inden for et minut

Leveret via webhook, så en nøgle committet klokken 14.00 er meldt 14.01. Et push, der lander oven i en scanning, der allerede er i kø, bliver slugt frem for at blive lagt i kø to gange.

Pull request · et check på ændringerne

Samme detektion af hemmeligheder, kun på de linjer, den pågældende pull request tilføjer, sendt tilbage som et GitHub-check med markeringer linje for linje — mens rettelsen stadig er en omskrivning af en gren og ikke en udskiftning af en nøgle.

03 · Risikodimensioner

Tretten dimensioner, og hvor hver konklusion kommer fra

Hver dimension har sit eget afsnit på fundets detaljeside og tre niveauer af vejledning: teknisk detalje, en trin-for-trin med konkrete eksempler, og en forklaring i almindeligt sprog. Hver eneste af dem kan lukke sig selv.

DimensionHvad den finderKilde
Kendte sårbarhederPakker med offentliggjorte sikkerhedsadvarsler, i hele det transitive træOSV.dev
Prioritering efter udnyttelseHvilke af dem der er bekræftet udnyttet — eller statistisk set er de næsteCISA KEV + FIRST EPSS
Ondsindede pakkerPakker udgivet for at stjæle adgangsoplysninger eller installere en bagdørOpenSSF-advarsler via OSV
Hemmeligheder i kodenAPI-nøgler, betalingsnøgler og databaseadgangskoder i arbejdstræetTarball-scanning i hukommelsen, ~45 udstedersignaturer
Hemmeligheder i git-historikkenOplysninger slettet i koden, men stadig mulige at hente fremGennemgang af de nyeste commit-ændringer, adskilt fra ovenstående
Forældet / udløbetPakker langt bagud eller ude over deres understøttede levetid8 pakke-registries + endoflife.date
UvedligeholdtAfhængigheder forfatteren har udfaset, forladt eller holdt op med at rørenpm deprecated / Packagist abandoned / manglende aktivitet
LicensrisikoLicenser, der juridisk kan række ind i dit eget produkt, fx stærk copyleftLicensvurderinger fra SBOM + registry som reserve
TyposquattingPakkenavne, der ligger ét tegns ændring fra en populær pakkeOffline Damerau-Levenshtein mod lister over populære pakker
Pakkers omdømmeHelt nye pakker — slopsquatting-angrebet, der rammer AI-foreslåede navneOprettelsesdato i registry (npm / PyPI / Packagist)
Dependency confusionInterne pakkenavne, som hvem som helst kan overtage på et offentligt registryTjek af eksistens på det offentlige registry
Container-base-imagesStyresystem-images ude over deres levetidDockerfile / compose + endoflife.date
CI/CD-pipelineSvagheder i den automatik, der ligger inde med dine deployment-nøglerGennemgang af .github/workflows

To oplysninger følger med hver afhængighed og ændrer, hvordan alt ovenstående skal læses: kæden der trak den ind, og om den kun bruges under udvikling.

04 · Designnoter

De dimensioner, hvor designet er produktet

Flere af dem er nemme at lave dårligt og svære at lave brugbart. Det her er, hvad forskellen består i.

Prioritering gør en liste til en arbejdskø

Alvorlighed siger, hvor slemt et hul ville være. KEV siger, at udnyttelse er observeret. EPSS giver en 30-dages sandsynlighed for den lange hale, KEV ikke dækker. Tre niveauer — udnyttet i virkeligheden, sandsynligt mål (EPSS ≥ 0,5), forhøjet risiko (≥ 0,10) — og sårbarhedstabellen sorterer først efter udnyttelse, derefter efter alvorlighed. Selve fundet er strengt, så det aldrig råber ulv.

Hemmeligheder: to adskilte gennemgange, plus omgåelse

Arbejdstræet streames som en tarball og parses udelukkende i hukommelsen. Historikken gennemgår de nyeste commit-ændringer og melder kun oplysninger, arbejdstræet ikke længere indeholder — så de to fund aldrig overlapper, og historik-fundet er præcis den type læk, hvor man "slettede linjen". En tredje gennemgang fanger nøgler, der er sat sammen af tilstødende tekststumper eller pakket ind i base64; begge kører kun signaturregler, aldrig entropi, fordi rekonstrueret tekst ser tilfældig ud af helt uskyldige grunde.

Selve værdien bliver aldrig gemt

Et fund om en hemmelighed bærer en fil, en linje, den detektor der matchede, og et maskeret uddrag — sk_l…(28 tegn). Den rå nøgle bliver ikke gemt, ikke logget og ikke lagt i noget, der sendes tilbage til GitHub. Samme disciplin gælder markeringerne i pull request-checket.

Pakkers omdømme, rettet mod slopsquatting

AI-assistenter importerer med fuld overbevisning pakker, der ikke findes; angribere registrerer netop de plausible navne, og assistenterne bliver ved med at anbefale dem. Sådan en pakke ligger ikke én redigering fra noget populært, så typosquatting er blind over for den, og på dag ét nævner ingen advarsel den, så malware-feedet er det også. Det ene, den ikke kan forfalske, er en historie — derfor er alder den eneste udløser: en direkte afhængighed, der er udgivet første gang inden for 90 dage. Installationsscripts, et manglende kildekode-repository og en enlig vedligeholder er skærpende omstændigheder på en ung pakke, aldrig fund mod en etableret. Fundet lukker sig selv, når pakken bliver gammel nok.

Dependency confusion kræver ingen opsætning

En direkte afhængighed, hvis navn giver 404 på sit offentlige registry, er eksponeringen, uanset hvem der ejer den — en angriber kan udgive det navn, og dit næste build kan tage deres. Et privat registry konfigureret i repositoryet er angrebets forudsætning og hæver konfidensen; npm-workspaces bliver genkendt, så den uskyldige monorepo-forklaring bliver tilbudt frem for begravet.

CI/CD graderet efter foranderlighed

Et workflow kører med repositoryets hemmeligheder og en skrive-token, så en svaghed dér rækker helt ind i deployment-vejen (se GitHub Actions-sikkerhed). Ikke-fastlåste actions graderes efter, hvor foranderlig referencen er — tredjeparts-gren er høj, tredjeparts-tag er middel, et førstepartstag lavt. At gradere førstepartstags højere ville få hvert eneste repository på GitHub til at lyse rødt for at følge GitHubs egen dokumentation. pull_request_target kombineret med et checkout af pull request'ens kode behandles som kritisk.

05 · Dækning

Økosystemdækning, sagt på det niveau hvor det faktisk passer

Dækningen er ikke ens overalt, og en scanner, der antyder noget andet, vildleder dig. Native parset betyder autoritativt: præcise versioner og en reel opdeling i direkte og transitive, hvor formatet har en.

NATIVE
npm, Python, PHP, Go, Maven, Ruby, Rust
package-lock.json, yarn.lock (klassisk og Berry), requirements.txt, poetry.lock, Pipfile.lock, composer.lock, go.mod, pom.xml, Gemfile.lock, Cargo.lock. Kundens manifester behandles som input, der ikke kan stoles på: XML-parsing afviser DOCTYPE fuldstændigt, hvilket lukker XXE ved roden, og der findes en test, der forsøger at læse /etc/passwd igennem den.
NATIVE
Gradle, i faldende grad af sikkerhed
gradle.lockfile først (en rigtig lockfile — præcise versioner, transitive inkluderet), derefter gradle/libs.versions.toml, derefter de bogstavelige koordinater i build.gradle(.kts), idet settings.gradle-includes følges. En version skrevet som en variabel, et + eller et interval står blank — buildet skulle køre for at vide det — og Gradle bliver ved med at være markeret som et build, vi måske ikke har læst fuldt ud, fordi det at lave "vi kunne ikke læse det her" om til en ren attest er præcis den fejl, der er værd at undgå.
MAVEN
Parent-POM'er, importerede BOM'er og multi-modul-builds
En pom.xml er et manifest, ikke en lockfile: i Java-verdenen angiver den som regel ingen af sine afhængigheders versioner — de kommer fra en parent. Vi følger den samme vej, som Maven gør: POM'ens egen dependency management, op ad parent-kæden og derefter ind i importerede BOM'er. Multi-modul-builds følges bredde-først med properties nedarvet ned ad grenen, fordi en aggregators rod-POM ofte slet ingen afhængigheder erklærer, og at læse den alene ville melde repositoryet som tomt. ${project.version} hører til den POM, der skriver den — at dele ét property-kort fik en BOM til at arve kundens projektversion og opløse en pakke til en udgivelse, der ikke findes. En opdigtet version er værre end en blank: blank bliver meldt som ikke tjekket, mens en forkert version bliver slået op mod advarsler som en kendsgerning.
BEREGNET
Python-transitive uden lockfile
En almindelig requirements.txt fastlåser kun det, forfatteren selv har skrevet; pip opløser resten ved installation og skriver ingen lockfile, så det meste af et Python-projekts reelle angrebsflade ville ganske enkelt mangle — hverken meldt som risikabelt eller meldt som ikke tjekket. Vi går de erklærede krav igennem bredde-først og vælger den nyeste stabile udgivelse, der opfylder hver PEP 440-specifikation. Hver sådan række er markeret beregnet — et stærkt estimat af, hvad en frisk installation giver, aldrig den fastlåste kendsgerning, en lockfile angiver — og en betingelse, der ikke kan opfyldes, opløses til ingenting; det bliver talt op og meldt frem for gættet. Et repository med en rigtig Python-lockfile bliver ikke rørt.
GRAF
NuGet og alt andet, GitHub kan opløse
GitHubs dependency graph udfylder resten. Bemærk, at den melder en pakke uden version, hver gang den ikke kan udfolde en property-reference; en versionsløs dublet af en pakke, de native parsere allerede har opløst, bliver droppet frem for at leve videre som et spøgelse.
MELDT
Hvad der ikke kunne læses
Hver scanning åbner med et dækningspanel: hvilke manifester der blev fundet, hvilke økosystemer der blev opløst, hvor mange rækker der er beregnede frem for fastlåste, og hvad der blev sprunget over. Grænser bliver meldt, aldrig tavse — en afkortet liste, der skriver "alle N er registreret", læses som fuld dækning, og det er den ikke.
06 · Dokumentation ud af systemet

SBOM og VEX, genereret ud fra den scanning, du allerede har kørt

Leveret som en fil-download, fordi standardværktøjer forventer selve dokumentet og ikke en indpakning.

SPDX 2.3

Det format, indkøb, revisorer og lovgivning beder om ved navn. En licens, vi ikke genkender, udstedes som NOASSERTION frem for et gæt — værktøjer nedstrøms behandler en SBOM som en kendsgerning, så et gæt breder sig som en.

CycloneDX 1.5

Det, sikkerhedsværktøjer læser, og det har en indbygget plads til sårbarheder — så eksporten bærer det, vi ved om fortegnelsen, ikke bare fortegnelsen. Begge formater genereres ud fra samme scanning, så de stemmer overens af konstruktion.

VEX: hvad en SBOM ikke svarer på

En SBOM siger, hvad softwaren indeholder; en VEX siger, hvad leverandøren har besluttet om hver kendt sårbarhed. Kvittér-med-begrundelse-arbejdsgangen har indsamlet præcis det, så status oversættes til en CycloneDX-analysetilstand med menneskets egen note vedhæftet. En advarsel, ingen endnu har vurderet, står som under vurdering, aldrig udeladt — en VEX, der kun nævner de flatterende poster, er ingenting værd.

NIS2 kræver allerede forsyningskædesikkerhed af de virksomheder, der er omfattet, og deres leverandører mærker det som et spørgeskema. Cyber Resilience Act faser krav om softwarestykliste ind hen over 2026-27. Det her er den billigste måde at have svaret klar.

07 · Adgang og tillidsgrænser

Hvad vi får lov til, og hvad vi gør med det

Læseadgang til indhold, pr. repository

En GitHub App pr. kunde, oprettet og installeret med ét klik, med læseadgang til repository-indhold — det mindste GitHub tilbyder — på de repositories, du vælger enkeltvis. Den kan ikke skrive kode, åbne pull requests eller ændre indstillinger. Pull request-checket tilføjer præcis to rettigheder: checks:write til at sende resultatet og pull_requests:read til at hente ændringerne. Begge er låst fast af en test, så en bredere tilladelse ikke kan snige sig ubemærket ind i manifestet.

Kildekode analyseres i hukommelsen

Repositoryet streames som en tarball og parses i hukommelsen. Kundens kildekode bliver aldrig skrevet til disk og aldrig gemt. Det, der bliver liggende, er den afledte fortegnelse og fundene.

Webhooken verificerer, før den læser

Den er platformens eneste uautentificerede skrivevej, og hver beslutning i den følger af det. HMAC'en verificeres over den rå request-body, før ét eneste felt bliver parset — at genserialisere et parset objekt ændrer byte-rækkefølgen og får hver verifikation til at fejle — med konstant-tids-sammenligning. Ingen konfigureret hemmelighed betyder en hård fejl, aldrig "accepteret": en instans, der ikke kan verificere, må ikke handle på ubekræftede påstande, heller ikke påstanden om at en kunde har afinstalleret.

Identiteten kommer fra vores egne data

Kunden slås op ud fra installations-id'et i vores egen database, aldrig ud fra repository-navnet i beskeden. En gyldig signatur beviser, at GitHub har sendt beskeden; den beviser ikke, at afsenderen må handle på en given kundes data. Nul eller flere match droppes frem for at blive gættet.

En fejl bliver aldrig et grønt flueben

Kan vi ikke hente en pull requests ændringer, sender vi slet intet check — en godkendelse, scanneren ikke har fortjent, er værre end tavshed. Kan et check ikke sendes, siger vi præcis det, så den ansvarlige kan give rettigheden frem for at undre sig.

Opdagelse af tavse fejl

Én webhook-hemmelighed betjener hver installation, så en uoverensstemmelse fejler for alle kunder på én gang, uden andet end afvisninger i en log, ingen læser. Afvisninger i træk er signalet — tælleren nulstilles ved enhver accepteret levering, så almindelig støj aldrig hober sig op til falsk alarm — og en stribe af dem bliver eskaleret.

08 · Præcision

Præcisionen bliver målt på begge sider af en udrulning

Det her produkt bliver brugt af folk, der tror på alt, hvad det siger — eller holder op med at tro på noget som helst af det ved den første fejl, de tilfældigvis opdager. Derfor bliver præcisionen — og lige så vigtigt: om vi overser noget — målt, ikke påstået.

Før udgivelse: en korpusport i hvert build

Hver dimension i motoren kører offline mod et plantet repository, hvis forventede fund er skrevet ned i hånden i et facit. Kravet er nøjagtig ens mængder i begge retninger: en manglende post betyder, at vi har overset et rigtigt fund — et værn, der er blevet så bredt, at det sluger et rigtigt fund, hvilket én gang kostede otte plantede hemmeligheder i én enkelt ændring — og en ekstra post er et tab af præcision. Ingen af delene kommer ud. Facit er specifikationen, ikke et spejl af koden; en regel, der legitimt ændrer adfærd, opdaterer facit i samme commit, med begrundelsen.

Fælderne er den interessante del

Plantet ved siden af de rigtige fund ligger hver eneste falske positiv, vi har lært af i produktion: referencer til miljøvariabler over for standardværdier med en rigtig værdi i, dokumenterede eksempelnøgler, danske pladsholder-adgangskoder, SHA-fastlåste actions, Dockerfile-trinaliasser, det YAML-on:-nøgleord der parses som en boolean. At designe korpusset fandt i sig selv en rigtig fejl — en udløbsregel, der aldrig udløste for Django stavet med det sædvanlige store D.

Efter udgivelse: falske positive bliver talt

"Ikke et rigtigt fund" er sin egen handling, bevidst adskilt fra at kvittere. At kvittere er en risikobeslutning om dit system; en indberetning af en falsk positiv er dokumentation om vores detektionskvalitet. Det bliver talt op pr. regel og vist som et kvalitetskort, så en støjende detektor er synlig for os, før den brænder din tillid af.

Ende-til-ende-fixtures med offentliggjort facit

To private repositories bakker den offline port op: ét med 108 plantede elementer på tværs af ti dimensioner, bygget bevidst svært — syntetiske værdier med korrekte udstederformater og uden pladsholder-ordforråd, så vores egne filtre ikke kan dække over et overset fund — og ét Maven-aggregator-projekt, hvis rod-POM erklærer ingen af sine fem afhængigheder. Begge fandt rigtige fejl, som ingen unittest havde fanget.

09 · Principper

Fire regler, koden rent faktisk følger

Det er ikke idealer. Hver enkelt findes på grund af en bestemt måde at tage fejl på, som vi helst ikke vil gentage.

En fejl er aldrig en ren attest.Hvert eksternt opslag falder tilbage til "ikke tjekket" med en begrundelse — aldrig til "intet fundet". Et utilgængeligt udnyttelses-feed betyder ikke, at intet bliver udnyttet; en 503 fra et registry betyder ikke, at pakken ikke findes. Et repository, vi ikke kan læse, giver slet ingen opsamling, så det sidste komplette resultat bliver stående frem for at blive erstattet af et tomt.
Grænser bliver meldt, ikke fortiet.Hver eneste grænse — commit-vinduet, antal opslag, BOM-importer — siger, hvad den sprang over. En afkortet liste, der læses som fuld dækning, er en løgn ved udeladelse.
Aldrig fremstille et skøn som en kendsgerning.En licens, vi ikke genkender, er NOASSERTION. En version, der ikke kan opløses, står blank og tælles som ikke tjekket, frem for at få et plausibelt tal, der så ville blive slået op mod advarsler og meldt som sikker viden.
Præcision er produktet.En fundliste, folk holder op med at læse, er ingenting værd, så den uskyldige forklaring kommer først overalt, hvor det uskyldige tilfælde er det almindelige, og den skarpe tone er forbeholdt signaler, der næsten aldrig er uskyldige — malware og bekræftet udnyttelse. Testfixtures, pladsholderfiler og dokumenterede eksempler bliver filtreret bevidst fra, hver med en test så støjen ikke kan vende tilbage.
10 · Begrænsninger

Hvad CodeControl ikke gør

Sagt her frem for opdaget senere, fordi en køber, der selv finder en begrænsning, holder op med at stole på alt andet på siden.

Det læser, hvad repositoryet erklærer

Ikke hvad buildet producerer. For de fleste projekter er det det samme. Hvor et build beregner sine afhængigheder undervejs, er nogle uden for rækkevidde — og rapporten siger det frem for i stilhed at vise færre.

Ingen analyse af jeres egen kode

Der er ingen statisk analyse af håndskrevet applikationskode, og det er bevidst. For den her målgruppe er koden, I selv har skrevet, en lille del af det, I reelt kører, og regelbaseret kodeanalyse er den disciplin inden for sikkerhed, der giver flest falske positive. Præcisionen i alt det andet er mere værd end en støjende ekstra dimension.

Ikke alle økosystemer er lige dybe

Java, JavaScript, PHP, Python, Go, Ruby, Rust og .NET er godt dækket. Noget mere eksotisk afhænger af, hvad GitHub selv kan opløse — og scanningen melder, hvilke dele den ikke kunne nå.

Ikke en penetrationstest, ikke en garanti

Det melder, hvad der kan vides ud fra repositoryet. Det kan ikke se, hvordan applikationen opfører sig i produktion, og det forsøger ikke at udnytte noget. Til blikket udefra på et kørende site er det VulnControl

Verifikation af hemmeligheder er bevidst ikke bygget endnu

At tjekke, om en fundet nøgle stadig er aktiv hos sin udbyder, betyder at sende kundens rå nøgle ud af huset. Det skal designes sammen med gennemgangen af databehandlingen — tilvalg pr. kunde, kun læse-endpoints, aldrig gemt — ikke sættes på, fordi det demonstrerer godt.

Prisen er ikke offentliggjort endnu

Produktet er bygget og kører; den kommercielle beslutning er den udestående del, og i dag bliver det slået til pr. kunde i hånden. Tal med os, så siger vi det, som det er

CodeControl

Hold det op mod det, I bruger i dag

Kører I allerede en scanner til forsyningskæden, er den brugbare sammenligning prioriteringen, afhængighedskæderne og rapporteringen af dækning. Forbind ét repository og stil dem side om side.

Tilbage til CodeControl i almindeligt sprog