Gå til hovedinnhold

Nåbarhet

Et sårbarhetsvarsel for en avhengighet sier at en pakkeversjon er sårbar. Det sier ikke om programmet ditt kan nå den sårbare koden. Nåbarhet svarer på det for Go, ut fra binærfilene du faktisk leverer, og ut fra koden i repositoryet ditt for JavaScript og TypeScript (npm) og, på importnivå, Python (PyPI) og Java og Kotlin (Maven). Den viser deg også hvorfor. For Go analyseres i tillegg repositoryets egen kode (kildemodus); se nedenfor.

Hva som sjekkes

Go: binærfilene du leverer

Når fremforge skanner containerimagene i organisasjonens register på nytt, leses hver Go-binærfil som har et sårbarhetsfunn, av govulncheck i binærmodus. govulncheck leser binærfilens modulliste og symboltabell og sammenligner dem med Gos sårbarhetsdatabase, som navngir nøyaktig hvilke funksjoner hvert sårbarhetsvarsel gjelder.

  • Ingenting i imaget ditt bygges eller kjøres. Binærfilen leses som en fil.
  • Ingen tjeneste kalles. Sårbarhetsdatabasen er fremforges egen kopi av OSV-postene for Go, oppdatert daglig.
  • govulncheck (BSD-3-Clause) er låst til en utgivelse og oppdateres via Renovate.

Terraform- og OpenTofu-providere: binærfilene låsefilene dine låser

Et funn i en Terraform- eller OpenTofu-provider er en Go-modul som er bygget inn i provider-binærfilen som .terraform.lock.hcl låser. fremforge leser den binærfilen med govulncheck i binærmodus, som for en Go-binærfil i et image, og funnet får vurderingen reachable når en berørt funksjon er lenket inn i provideren, og not reachable når modulen (eller pakken) finnes i binærfilen, men ingen av funksjonene sårbarhetsvarselet navngir.

  • Provider-utgivelser bygges uten symboltabell (-ldflags=-s). Funksjonstabellen Go beholder under kjøring, finnes likevel; fremforge gjenoppretter det ene symbolet govulncheck trenger for å lese den, og resultatet blir det samme som for den samme provideren bygget med symbolene sine. Hvis symbolet ikke finnes, forblir vurderingen unknown (no_symbol_table).
  • Hver provider-versjon analyseres én gang, for alle organisasjoner som låser den, fra kopien i fremforges provider-speil. Ingenting fra repositoryet ditt brukes.
  • En provider-binærfil over 512 MiB (for eksempel hashicorp/aws) beholder vurderingen unknown (engine_failed).

Go: koden i repositoryet ditt

Når en avhengighetsskanning finner sårbare Go-moduler, kjører fremforge også govulncheck i kildemodus på den skannede commiten. Den typesjekker modulene dine og bygger en kallgraf fra main-pakkene dine, slik at den kan vise kallstien fra en linje i repositoryet ditt til den berørte funksjonen, selv når det ikke er bygget noe image fra den commiten.

Dette krever go-kommandoen, som et repository kan forsøke å styre. fremforge kjører den slik at ingenting fra repositoryet ditt kjøres, og ingenting hentes annet enn gjennom organisasjonens avhengighetsproxy. Utformingen ble gjennomgått før den ble lansert.

  • Ingenting i repositoryet ditt kjører. Ingen go generate, ingen tester, ingen bygging, ingen cgo (CGO_ENABLED=0), ingen -toolexec. Bare Go-verktøykjedens egen typesjekker leser koden din.
  • Ingen annen verktøykjede. En toolchain-linje ignoreres (GOTOOLCHAIN=local). En go-linje som er nyere enn fremforges Go, gjør modulen unknown (build_failed). fremforge holder sin Go oppdatert via Renovate.
  • Ingen versjonskontroll og ikke noe annet nettverk. Moduler hentes bare fra organisasjonens avhengighetsproxy, gjennom et relé som legger til fremforges skannelegitimasjon, slik at pakkepolicyen din gjelder. Det finnes ingen reserveløsning til en versjonskontrollvert. Hvis organisasjonen din har slått av avhengighetsproxyen, leser skanningen i stedet moduler fra fremforges egen skannebuffer på den samme proxyen. Den bufferen inneholder bare offentlige moduler fra proxy.golang.org, hver av dem sjekket mot sum.golang.org, og bruker ingen av dine legitimasjoner, så pakkepolicyen din gjelder ikke for de lesingene. En organisasjon der proxyen avviser en modul på grunn av policyen, får unknown for den; skanningen går aldri utenom proxyen din.
  • Private moduler etterspørres aldri. En modul under frem.sh, eller som matcher et GOPRIVATE-, GONOPROXY- eller GONOSUMDB-mønster som repositoryet ditt deklarerer (i CI-workflowene, go.env, .envrc, .env eller Makefile), avvises før noen forespørsel forlater skanningen. Stien sendes aldri til avhengighetsproxyen, til proxy.golang.org eller til sum.golang.org, og alt som trenger den, blir unknown (build_failed). Den samme regelen gjelder for Go-oppslagene for lisens, utgivelsesalder og avhengighetsgraf. Se hva som når Google for offentlige moduler.
  • Innstillingsfilene dine leses ikke. En innsjekket GOFLAGS-fil, go.env eller .config/go/env, en vendor/-katalog og en .netrc ignoreres. Symbolske lenker følges ikke.
  • Avvist før analysen, som unknown (build_failed): en modul som styres av en go.work (den endrer hvilken kode som bygges), en replace til en absolutt sti eller utenfor repositoryet, og en modulsti som navngir et versjonskontroll-repository direkte (….git).
  • Skilt fra fremforges legitimasjon. Analysen kjører i sin egen container som ikke har noen legitimasjon og ikke når noe annet enn reléet. Den har egne grenser for minne og CPU.
  • Grenser: 20 moduler, 20 000 filer og 128 MiB av repositoryet ditt per skanning, 512 MiB modulnedlastinger og et tidsbudsjett på 3 minutter per skanning. Over en grense blir unknown.
  • Tester (_test.go) analyseres ikke, som i binærmodus. Standardbiblioteket vurderes bare i binærmodus: kildemodus ville lest det i fremforges Go-versjon, ikke din.
  • Den får aldri skanningen til å feile og endrer aldri statusen fremforge/dep-scan.

JavaScript og TypeScript: koden i repositoryet ditt

Når en avhengighetsskanning finner sårbare npm-pakker, kjører fremforge Jelly, en statisk kallgrafanalysator for JavaScript og TypeScript fra Aarhus Universitet, på den skannede commiten. Den sjekker om koden din laster den sårbare pakken, direkte eller gjennom andre pakker.

  • Jelly leser koden din. Den kjører den aldri: ingenting installeres, ingen pakkekode kjører og ingen installasjonsskript kjører.

  • Pakkene på veien til en sårbar pakke hentes etter navn og versjon og pakkes ut som data. Hver av dem sjekkes mot integritetshashen i låsefilen din, og repositoryets .npmrc brukes ikke. De hentes gjennom organisasjonens avhengighetsproxy (se Hvor pakkefilene kommer fra).

  • Hver tarball leses som en strøm. Den sjekkes mot integritetshashen sin etter hvert som den kommer inn, og bare filene Jelly leser, skrives: .js, .mjs, .cjs, .jsx, .ts, .mts, .cts, .tsx og .json. Native binærfiler og andre store filer hoppes over uten å bli tatt vare på, så en pakke som onnxruntime-node (108 MiB) analyseres som alle andre. Filene beholdes bare når hashen stemmer.

  • Grenser: en tarball på opptil 512 MiB, 2 GiB utpakket, 100 000 oppføringer, 10 000 skrevne filer og 16 MiB per skrevet fil. Alle pakkene som legges ut for én låsefil, kan til sammen ta opptil 96 MiB skrevne filer. En pakke over en grense gjør funnene som trenger den, unknown (build_failed). En fil som hoppes over på grunn av størrelsen, lar aldri et funn bli unreachable.

  • Støttede låsefiler:

    LåsefilVersjonerIntegritet sjekkes mot
    package-lock.json, npm-shrinkwrap.jsonlåsefilversjon 2 eller 3 (npm 7 og nyere)låsefilen
    pnpm-lock.yaml5.x, 6 og 9låsefilen
    yarn.lock, classicyarn 1låsefilen (integrity, eller SHA-1 i en eldre resolved-URL)
    yarn.lock, berryyarn 2 og nyere (__metadata versjon 4 og nyere)integriteten registeret ditt publiserer for den versjonen, fordi berrys checksum dekker yarns eget bufferarkiv og ikke npm-tarballen. En pakke der den publiserte integriteten ikke kan leses, hentes ikke.
    bun.locktekstformat (bun 1.2 og nyere)låsefilen

    For yarn classic, som ikke registrerer workspaces, leses også package.json ved siden av låsefilen og dens workspaces. bun.lockb, buns eldre binærformat, leses ikke: det er et udokumentert minnebilde som har endret seg mellom bun-versjoner. Funnene derfra blir unknown, og bevisene sier hvorfor. Andre låsefiler gir unknown.

  • Jelly (BSD-3-Clause) kjører inne i fremforges skannejobb og kaller ingen tjeneste. Den er låst til en utgivelse og oppdateres via Renovate.

  • Analysen har et tidsbudsjett på 2 minutter per skanning. Den får aldri skanningen til å feile. Den endrer statusen fremforge/dep-scan bare hvis organisasjonen din har slått på ikke å blokkere på funn som ikke er nåbare.

Python, Java og Kotlin: importene i repositoryet ditt

Når en avhengighetsskanning finner sårbare PyPI- eller Maven-pakker, sjekker fremforge om koden din importerer dem. Dette er bare på importnivå: det forteller deg at en pakke lastes, aldri at den sårbare koden kjører, og det gir aldri unreachable.

  • Python. .py-filene dine parses med Pythons egen ast-modul, som bare parser. Ingenting importeres eller kjøres. fremforge leser import- og from … import-setninger, og kall til importlib.import_module(...) og __import__(...) med et bokstavelig navn. En fil som ikke kan parses med gjeldende Python, for eksempel Python 2-kode, leses i stedet linje for linje etter importsetninger. Relative importer (from . import x) er dine egne moduler og hoppes over, det samme gjelder virtuelle miljøer (.venv, venv, site-packages) og symbolske lenker.

  • Python, gjennom andre pakker. Når koden din ikke selv importerer en sårbar pakke, følger fremforge pakkene koden din importerer: den leser koden deres fra wheel-filene på samme måte, med start i modulene koden din importerer, og følger bare deres egne importer. Hvis kode som nås på den måten, importerer den sårbare pakken, blir funnet Importert, og bevisene viser stien: importen din, deretter importen inne i hver pakke, for eksempel idna via requests. En modul som ingenting laster (som en pakkes help.py), og importer under if TYPE_CHECKING: følges ikke. Denne gjennomgangen går høyst tre pakker dypt og leser høyst 40 wheel-filer på opptil 16 MiB hver per skanning. Den legger bare til Importert-vurderinger; en sti den ikke kan følge, lar funnet forbli unknown.

  • Java, Kotlin, Groovy og Scala. fremforge leser import-setninger, fullt kvalifiserte klassenavn i koden, og Class.forName("…") og loadClass("…") med et bokstavelig navn. Kommentarer og strengliteraler ignoreres, og det samme gjør build/ og target/. Ingenting kompileres.

  • Java og Kotlin, gjennom andre pakker. Når koden din ikke selv importerer en sårbar Maven-pakke, følger fremforge pakkene koden din importerer, i de kompilerte klassene deres. Den starter i klassene koden din importerer (alle klassene i pakken ved en jokertegnimport import a.b.*). Derfra følger den klassene de bruker: hver klasse en metode kaller, oppretter, caster til eller leser et felt fra, og hver superklasse og hvert grensesnitt. Disse leses fra konstantpoolen i hver klassefil. Hvis en klasse som nås på den måten, bruker en klasse fra den sårbare pakken, blir funnet Importert. Bevisene viser stien: importen din, deretter kildefilen og linjen inne i hver pakke der den neste brukes. Et eksempel er commons-text via commons-configuration2. En klasse ingenting når, følges ikke, og heller ikke en klasse som lastes etter navn fra en streng. Klassefiler leses som data: ingen klasse lastes eller kjøres, og ingen JVM er involvert. Denne gjennomgangen går høyst tre pakker dypt og leser høyst 40 JAR-filer på opptil 32 MiB hver per skanning, én om gangen. Den legger bare til Importert-vurderinger; en sti den ikke kan følge, lar funnet forbli unknown.

  • Hvilke navn en pakke tilbyr, hentes fra fillisten i det publiserte arkivet, lest som data:

    • PyPI: wheel-filen for den versjonen. En navneromspakke løses opp til sin første reelle pakke, for eksempel google.protobuf for protobuf.
    • PyPI, en utgivelse uten wheel (bare sdist): kildearkivet, lest som data og aldri installert. setup.py verken kjøres eller leses. Navnene hentes fra pakkelistene i setup.cfg eller pyproject.toml (setuptools, hatch, flit og poetry), ellers fra katalogene som inneholder en __init__.py, på toppnivå, under src/ eller under en katalog som lib/. Dermed tilbyr pysaml2 saml2 og pycrypto Crypto. PKG-INFO må navngi det samme prosjektet. Arkiver på opptil 16 MiB leses (.tar.gz, .tar, .zip). En utgivelse som ikke finnes i noen indeks, eller en sdist som ikke navngir noe (for eksempel en .tar.bz2), faller tilbake til prosjektnavnet, slik at requests står for import requests; feltet mapping i bevisene sier fra om det.
    • Maven: JAR-filen på Maven Central, og Java-pakkene klassene ligger i.

    For en wheel- eller JAR-fil hentes bare arkivets katalog, med HTTP range-forespørsler, så selv en stor fil koster bare noen få kilobyte. Gjennomgangen gjennom andre pakker leser hele wheel- eller JAR-filen for hver pakke den følger, og en sdist leses alltid i sin helhet. Ingenting installeres, bygges eller kjøres.

  • Repositoryet ditt bygges ikke. Nåbarhet med kallgrafer for Java, som osv-scanners eksperimentelle JAR-analyse eller jdeps, krever en bygget JAR. En skanning av en pull request bygger ikke prosjektet ditt, så de verktøyene brukes ikke.

  • Analysen har et tidsbudsjett på 1 minutt per økosystem per skanning og kjører parallelt med npm-analysen. Den får aldri skanningen til å feile og endrer aldri statusen fremforge/dep-scan.

Hvor pakkefilene kommer fra

npm-tarballer, PyPI-indekser og wheel-filer og Maven-JAR-er leses gjennom organisasjonens avhengighetsproxy, på en intern rute som bare fremforges skannetjeneste kan nå. Organisasjonens pakkepolicy, buffer, lagringsgrense og upstream-frekvens gjelder derfor for dem som for enhver annen pull, og det skanningen henter, bufres for byggene dine.

  • Hvis policyen din avviser en pakke (for eksempel skadevare, en for ny utgivelse eller en lisensregel), henter skanningen den ikke noe annet sted. Funnene som trenger den, blir unknown (build_failed), og bevisene navngir proxyens beslutning.
  • Hvis organisasjonen din har slått av avhengighetsproxyen, eller proxyen ikke kan svare, leses filene i stedet fra de offentlige registrene (npmjs, PyPI, Maven Central), som før.
  • Filer skanningen henter, teller mot organisasjonens proxylagring som alle andre bufrede filer.

Nivåene

En vurdering har et nivå: hvor mye motoren kunne se.

NivåBetydning
functionSårbarhetsvarselet navngir de berørte funksjonene, og motoren så etter en sti til dem. Det er dette govulncheck gir for Go.
importSårbarhetsvarselet navngir ingen berørte funksjoner. Motoren kan bare si om den sårbare pakken lastes.

npm-sårbarhetsvarsler navngir nesten aldri berørte funksjoner. Da dette ble målt 2026-10-12, gjorde ingen av de 230 287 npm-postene i OSV-databasen det. Vurderinger for JavaScript og TypeScript er derfor på importnivå: de forteller deg at koden din laster den sårbare pakken, ikke at den kaller den sårbare koden. Hvis et npm-sårbarhetsvarsel faktisk navngir berørte funksjoner, sjekker Jelly dem på funksjonsnivå.

Vurderinger for Python og Maven er alltid på importnivå. Den samme målingen fant data om berørte funksjoner i 2 av 26 221 PyPI-poster og i ingen av de 7 190 Maven-postene.

De tre vurderingene

Hvert avhengighets- og imagefunn har én av disse:

VurderingGo (govulncheck)JavaScript og TypeScript (Jelly)Python, Java og Kotlin (importnivå)
NåbarEn berørt funksjon er lenket inn i binærfilen. Go-linkeren fjerner kode som ingenting kan kalle, så en lenket funksjon er en som programmet ditt kan nå. Markøren navngir funksjonen, for eksempel html.Renderer.renderLink. I kildemodus: en kallsti fra koden din når en berørt funksjon; markøren gir filen og linjen for det siste kallet i repositoryet ditt før stien går inn i avhengigheten, for eksempel handleren din i stedet for main. Hele stien står i bevisene.Importnivå, vist som Importert: koden din laster pakken i den sårbare versjonen, direkte eller gjennom andre pakker. Funksjonsnivå, vist som Nåbar: et kall i koden din kan nå en berørt funksjon. Markøren gir filen og linjen i repositoryet ditt, for eksempel src/session.ts:12.Vist som Importert: koden din importerer en modul eller Java-pakke som den sårbare pakken tilbyr. Markøren gir filen og linjen for importen, for eksempel app/main.py:2.
Ikke nåbar (unreachable)Modulen finnes i binærfilen i en berørt versjon, sårbarhetsvarselet navngir de berørte funksjonene, govulncheck kjørte ferdig, og ingen av de funksjonene finnes i binærfilen. I kildemodus: modulen brukes i en berørt versjon, govulncheck fant ingen kallsti til noen berørt funksjon, og ingenting govulncheck ikke kan følge (refleksjon, filer for andre plattformer, cgo, plugins), finnes i koden din.Sårbarhetsvarselet navngir de berørte funksjonene, Jelly kjørte ferdig med alle pakkene på veien tilgjengelige, og ingen kall i koden din når en av dem. Uten slike funksjonsdata blir en pakke som koden din aldri laster, unknown, ikke unreachable.Aldri. Importer inne i andre pakker følges bare så langt de navngir en modul eller klasse bokstavelig, så en pakke som koden din ikke ser ut til å laste, kan likevel bli lastet.
UkjentAlt annet. Dette er standardverdien, og den behandles aldri som trygg.Det samme.Det samme, inkludert alle pakker som koden din ikke importerer.

unreachable krever at alle betingelsene er oppfylt. Mangler en inndata, blir det alltid unknown, med årsak:

ÅrsakHvorfor
no_symbol_dataSårbarhetsvarselet navngir ikke de berørte funksjonene, så fraværet av en sti beviser ingenting. For npm er dette den vanlige årsaken når koden din ikke laster pakken. For Python og Maven er det årsaken hver gang koden din ikke importerer pakken.
no_symbol_tableGo: binærfilen ble bygget med -ldflags=-s. Symbolene kan ikke leses, så ingen av vurderingene kan fastsettes. Bygg uten -s (det er greit å beholde -w) for å få vurderinger. Terraform-providere: symbolet fremforge gjenoppretter, ble ikke funnet i denne binærfilen.
build_failedGo i kildemodus: modulen ble avvist før analysen (se over), kunne ikke lastes, eller en modul kunne ikke hentes fra avhengighetsproxyen din. npm: låsefilen har ikke et av de støttede formatene, eller en pakke på veien kunne ikke hentes, var over en grense eller stemte ikke med integritetshashen sin. Python og Maven: wheel-, sdist- eller JAR-filen kunne ikke leses, for eksempel en artefakt med bare POM eller en som ikke finnes på Maven Central.
dynamic_codeKoden din laster moduler eller klasser med beregnede navn, så en manglende kallsti eller import beviser ingenting. npm: require(name) og import(name). Python: importlib.import_module(name) og __import__(name). Java: Class.forName(name) og loadClass(name). Go i kildemodus: pakken plugin eller //go:linkname.
reflectionGo i kildemodus: koden din kaller metoder via reflect (MethodByName, Method, Call), eller bruker text/template eller html/template når sårbarhetsvarselet navngir metoder. govulncheck kan ikke følge de kallene, så en manglende kallsti beviser ingenting.
build_constraintsGo i kildemodus: en fil som analysen ikke lastet, importerer andre pakker. Analysen laster koden din som for Linux på amd64 uten cgo, så en _windows.go-fil, en fil der //go:build-linjen utelukker Linux, eller en cgo-fil er ikke med i kallgrafen, og et kall som bare gjøres der, ville blitt oversett. En pakke som bare kan bygges med cgo (for eksempel et skrivebordsgrensesnitt på et verktøysett som bare finnes for cgo), utelates fra analysen i stedet for å få den til å feile: resten av modulen analyseres, og alle moduler den pakken importerer, får denne årsaken i stedet for unreachable.
timeoutAnalysen gikk over tidsbudsjettet sitt (5 minutter per image for Go, 2 minutter per skanning for npm, 1 minutt per økosystem per skanning for Python og Maven).
engine_no_matchGo: govulncheck rapporterte ikke denne modulversjonen som berørt av sårbarhetsvarselet, selv om imageskanneren gjorde det. Ingen av dem stoles mer på enn den andre.
oom_killedGo i kildemodus: analysen gikk tom for minne og ble stoppet, så ingenting ble avgjort.
engine_failedAnalysen kunne ikke kjøre på denne binærfilen eller dette repositoryet.
not_analysedIngen vurdering er beregnet: funnet er ikke skannet siden nåbarhet ble lagt til, eller et Go-funn har ikke noe image bygget fra commiten sin.
unsupported_ecosystemEt avhengighetsfunn utenfor Go, npm, PyPI, Maven og Terraform-providere, for eksempel NuGet eller Cargo.

Avhengighetsfunn

Go. Et Go-avhengighetsfunn får vurderingen sin i binærmodus, fra et image bygget fra nøyaktig den commiten. Der kildemodus er slått på (så langt fremforges interne organisasjoner), får det også en vurdering ved hver skanning, med kallstien i repositoryet ditt. Merk imagene dine med de to standard OCI-etikettene:

org.opencontainers.image.source=https://frem.sh/<org>/<repo>
org.opencontainers.image.revision=<full commit sha>

docker/metadata-action setter begge. Vurderingen gjelder bare commiten imaget navngir, og modulversjonene binærfilene ble bygget med. Hvis en Go-binærfil i det imaget ikke kunne leses, forblir avhengighetsfunnet unknown. Hvis flere binærfiler inneholder modulen, er funnet nåbart når en av dem når det.

Når begge modusene vurderer det samme funnet i den samme commiten, sletter ingen av dem den andre: en unknown fra den ene erstatter aldri en vurdering fra den andre, og not reachable fra den ene erstatter aldri reachable fra den andre. Bevis fra kildemodus har "mode": "source".

npm, PyPI og Maven. Vurderingene kommer med selve avhengighetsskanningen: hver skanning av en pull request, og skanningen av standardbranchen etter hver push (høyst én gang i timen). En vurdering hører alltid til commiten som ble skannet. Hvis den samme pakken og det samme sårbarhetsvarselet finnes i flere låsefiler, er funnet nåbart når en av dem når det.

Hvordan fremforge bruker det

Rangering. Funnlistene for Dependencies og Container images sorteres med nåbare først, deretter ukjente, deretter ikke nåbare. Innenfor hver gruppe sorteres de etter alvorlighetsgrad, deretter kjent utnyttet foran resten, deretter etter EPSS. Et funn er kjent utnyttet når en av CVE-ID-ene, dets egne eller sårbarhetsvarselets aliaser, er oppført som utnyttet i ENISAs EU Vulnerability Database eller i CISAs Known Exploited Vulnerabilities-katalog. Begge listene viser et Kjent utnyttet-merke med et verktøytips som navngir kilden: EU (ENISA EUVD), US (CISA KEV) eller begge, og over hver liste viser Bare kjent utnyttet bare de funnene (findings-API-ets ?known_exploited=true). Begge listene oppdateres daglig. Et Importert-funn rangeres sammen med de nåbare. Den samme rekkefølgen brukes av:

  • fanen Anbefalinger, der et kort (én oppgradering av én pakke i ett repository) får den mest nåbare vurderingen blant funnene det retter, og merkes Nåbar eller No call path;
  • Top fixable today i den ukentlige oppsummeringen, som viser vurderingen for hver rad;
  • findings-API-et med ?sort=risk.

Varsler. Når et åpent avhengighetsfunn blir nåbart, eller blir kjent utnyttet, får SIEM-en din straks en revisjonshendelse, og organisasjonens sikkerhetskontakter får en e-post, én gang per funn: se Funnvarsler. Kjent utnyttet, og nåbart med alvorlighetsgrad HIGH eller CRITICAL, sendes på e-post straks. Nåbart med alvorlighetsgrad MEDIUM eller LOW havner i hver persons daglige varseloppsummering, eller sendes straks til den som har slått av oppsummeringen. Oppsettsjekklisten under Sikkerhet › Oversikt viser hvilke av imagene dine som har Go-binærfiler uten symboler.

Gruppen som trolig ikke kan utnyttes. Funn som ikke er nåbare, flyttes til en sammenslått gruppe nederst i listen, med antallet i tittelen. De forblir synlige, kan velges og avvises, og de telles med i alle totaler.

Ingenting skjules eller avvises. En vurdering skriver aldri en avvisning. Den endrer et funns SLA bare når organisasjonen din slår på SLA-multiplikatoren. Som standard leser ikke commit-statusen (fremforge/dep-scan, fremforge/image-scan) vurderinger: det som blokkerer en merge eller en pull, er uendret. Det ene unntaket er den valgfrie policyen om ikke å blokkere pull requests på funn som ikke er nåbare, som bare gjelder fremforge/dep-scan.

SLA-multiplikator (valgfri)

En eier av organisasjonen kan forlenge SLA-en per alvorlighetsgrad for funn som er not reachable, under Sikkerhet › Prioriter › SLA for utbedring (/<org>/_admin/security/prioritise/sla), eller med unreachable_sla_multiplier på PUT /orgs/{org}/security/sla-policy. Verdien er et heltall fra 1 til 4. Standardverdien 1 betyr av.

  • Bare unreachable-funn forlenges. Nåbare og ukjente funn beholder alltid full SLA, og det samme gjør et funn som ikke er analysert.
  • Et kjent utnyttet funn (oppført av EU (ENISA EUVD) eller US (CISA KEV), se Rangering over) forlenges aldri, uansett alvorlighetsgrad og vurdering.
  • Et kritisk funn der EPSS-skåren er blant de øverste 10 % (persentil 0,90 eller høyere), forlenges aldri, uansett vurdering.
  • Fristen regnes alltid fra da funnet først ble sett. Når en senere skanning finner en kallsti, eller ikke kan avgjøre, gjelder full SLA straks igjen, så funnet kan gå rett over SLA. SLA-merkelappen sier da hvorfor.
  • Med multiplikatoren slått på viser en forlenget SLA-merkelapp en liten ×2 (eller ×3, ×4) og et verktøytips med begge fristene. Antallet over SLA i den ukentlige oppsummeringen, flisen på oversikten og SIEM-hendelsen code-security.sla.breached bruker de samme forlengede fristene.
  • Multiplikatoren endrer bare frister. Den endrer ikke hva som blokkerer en pull request, og den skjuler ingenting.

Hver endring revideres som code-security.sla_policy.updated, med forrige verdi.

Ikke blokker på funn som ikke er nåbare (valgfritt)

Som standard blokkerer hvert avhengighetsfunn på eller over blokkeringsterskelen din pull requesten, uansett vurdering. En eier av organisasjonen kan velge at et funn med not reachable ikke blokkerer fremforge/dep-scan. Dette er av til du slår det på.

Risikoen. En manglende kallsti er sterke bevis, ikke et bevis i streng forstand (se Hva statisk analyse ikke kan se). Hvis analysen overser en sti gjennom refleksjon, en plugin, en dynamisk import, avhengighetsinjeksjon eller kode utenfor repositoryet, eller sårbarhetsvarselet navngir feil funksjoner, lar en falsk not reachable en reell, nåbar sårbarhet bli merget. Slå dette på bare der du godtar det, og vurder å begrense det til repositoryene der du stoler på analysen.

Slå det på under Sikkerhet › Prioriter › Sjekker for pull requests (/<org>/_admin/security/prioritise/pr-checks), eller med PUT /orgs/{org}/security/dep-scan-unreachable-policy (se API). Du kan begrense det til en liste over repositoryer; en tom liste betyr alle repositoryene i organisasjonen.

Hva det endrer, og hva det aldri endrer:

  • Bare unreachable med bevis kvalifiserer. Funnets vurdering for pull requestens head-commit må være not reachable, beregnet av en motor med versjonen sin og de berørte funksjonene i sårbarhetsvarselet som den sjekket. I dag betyr det Go samt JavaScript og TypeScript. For Go gir govulncheck vurderingen i binærmodus når et image bygget fra pull requestens head-commit er skannet; en vurdering som kommer etter skanningen, gjelder fra pull requestens neste skanning. Der kildemodus er slått på (så langt fremforges interne organisasjoner), gir den også en vurdering ved selve skanningen av pull requesten. For JavaScript og TypeScript gir Jelly den når sårbarhetsvarselet navngir berørte funksjoner. Vurderinger for Python, Java og Kotlin er på importnivå og er aldri unreachable, så de blokkerer alltid.
  • unknown blokkerer alltid. Det finnes ikke noe valg for ikke å blokkere på unknown, og et funn som ikke er analysert, er unknown.
  • Skadevare og kjent utnyttede sårbarheter blokkerer alltid, uansett vurdering: et MAL--sårbarhetsvarsel eller et sårbarhetsvarsel merket som ondsinnet, og en sårbarhet der en av CVE-ID-ene er oppført som utnyttet av EU (ENISA EUVD) eller US (CISA KEV). Hvis fremforge ikke kan lese disse opplysningene under en skanning, slippes ingenting gjennom i den skanningen.
  • Ingenting skjules. Funnet lagres, listes, telles i alle totaler og varsles som alle andre. Det avvises ikke, og SLA-en er uendret (med mindre SLA-multiplikatoren også er slått på).
  • Bare pull requests. Skanningen av standardbranchen registreres nøyaktig som før.
  • Treff i blokkeringslisten og blokkeringsterskelen er uendret. Et funn under terskelen blokkerte aldri, og en nektet komponent blokkerer fortsatt.

Blokkeringen kommer tilbake. Når en senere skanning av pull requesten finner en kallsti, eller ikke kan avgjøre, blokkerer funnet igjen. En vurdering beregnet utenfor en skanning (govulncheck på et image), og at policyen slås av eller innsnevres, fanges opp innen en time: fremforge sjekker på nytt hver pull request som slapp gjennom på grunn av policyen, og beregner status, kommentar og revisjonshendelse på nytt. Det samme skjer når et funn blir kjent utnyttet.

Hva pull requesten viser. Statusen fremforge/dep-scan sier hvor mange funn som ikke blokkerte, for eksempel 2 finding(s); 1 at or above critical with no call path, not blocking (org policy). Kommentaren merker hvert slikt funn not blocking og lister dem under Not blocking: no call path (org policy) med motoren, versjonen, datoen for sårbarhetsdatabasen og funksjonene den sjekket. Et funn uten kallsti som likevel blokkerer, listes under Blocking although no call path was found, med årsaken (skadevare eller kjent utnyttet).

Revisjon. Hver endring av policyen revideres som code-security.deps.unreachable_policy.updated, med ny og forrige verdi, om den endret seg, og om den kom fra konsollen eller API-et. Hver skanning av en pull request mens policyen gjelder, registrerer i hendelsen code-security.dep_scan.ingest hvert funn som ikke blokkerte (unreachable_not_blocking, med motoren, versjonen og databasedatoen det ble lent på), og hvert som likevel blokkerte (unreachable_blocked_anyway, med why). En ny sjekk har trigger: unreachable_policy_recheck og årsaken. Begge når SIEM-endepunktene dine.

Når en vurdering endres: reachability_changed

En avvisning eller et unntak kan bygge på en vurdering. Når du avviser et avhengighets- eller imagefunn med vurderingen not reachable, eller ber om et unntak for det, registrerer fremforge vurderingen det ble lent på: motoren, versjonen, databasedatoen og commiten eller imaget den ble beregnet for. Avvisningspanelet sier fra om det.

Hver time sjekker fremforge disse avvisningene og unntakene. Når en skanning etter avvisningen finner det samme funnet reachable, eller ikke kan avgjøre (unknown):

  • tilbakekalles et unntak med årsaken reachability_changed;
  • tilbakekalles en vanlig avvisning: funnet åpnes igjen, og en avvisning for hele repositoryet som den laget, slutter å gjelde for senere skanninger;
  • varsler funnet igjen gjennom det samme sikkerhetsvarselet som en utløpt avvisning;
  • er begge revisjonshendelser (code-security.exception.revoked, eller code-security.deps.dismissal_revoked og code-security.images.dismissal_revoked) med vurderingen det ble lent på og den nye, og de når SIEM-endepunktene dine. Funnhendelsen sier det også: security.finding.exception_revoked, eller for en vanlig avvisning security.finding.dismissal_revoked, begge med transition_reason reachability_changed.

Et funn som ikke er analysert på nytt, beholder avvisningen sin: fraværet av en ny skanning er ikke en ny vurdering. En avvisning gjort mens vurderingen ikke var unreachable, registrerer ingenting og tilbakekalles aldri av denne sjekken, og avvisninger gjort før dette ble lagt til, sjekkes ikke. Hvis du avviste et funn av en grunn som ikke avhenger av nåbarhet, avviser du det på nytt etter tilbakekallingen; vurderingen er da ikke lenger unreachable, så den nye avvisningen blir stående.

Triagesignaler for SAST

SAST-funn har ingen kallgraf, så tre deterministiske signaler rangerer dem i stedet. Ingen AI-modell er involvert.

SignalHva det er
StedFra filstien: testkode (test/, __tests__/, *.test.ts, *_test.go, test_*.py, *Test.java og lignende), eksempler og dokumentasjon, tredjepartskode (vendor/, third_party/, node_modules/) og generert kode (*.pb.go, *.min.js, gen/, zz_generated* og lignende).
Taint-stiOpenGreps regler i taint-modus sporer data fra en kilde, for eksempel brukerinndata, til et sluk. Et treff med et spor merkes Taint-sti og rangeres over et treff som bare bygger på mønster. Bare opplysningen lagres, aldri sporet.
Ofte avvist herPersoner har avvist den samme regelen på minst 2 andre funn i dette repositoryet, eller 5 i organisasjonen, de siste 90 dagene. Boter, automatisk løsning og andre systemaktører teller ikke.

Et funn i test-, eksempel-, tredjeparts- eller generert kode, eller et som er merket som ofte avvist her, flyttes til en sammenslått gruppe Lower confidence nederst i SAST-listen, med antallet i tittelen. En taint-sti flytter ikke et funn ut av den gruppen: et taint-treff i en testfil er fortsatt i en testfil. Innenfor hver gruppe sorteres funnene etter alvorlighetsgrad, deretter taint-sti, deretter alder, eldste først.

Som gruppen som trolig ikke kan utnyttes, blir funn med lavere tiltro aldri skjult eller avvist: de beholder full SLA, telles overalt, og kan velges, rettes og avvises som alle andre. Findings-API-et for SAST returnerer signalene som et triage-objekt på hvert funn, og ?sort=risk lister funnene i denne rekkefølgen på tvers av sider.

Kommentar på pull requesten. Kommentaren fra avhengighetsskanningen sorterer funnene på samme måte og merker hvert med vurderingen når det finnes en for pull requestens commit: reachable med funksjonen eller filen og linjen, imported med filen og linjen (npm, Python, Java og Kotlin), eller no call path. Med policyen om ikke å blokkere på funn som ikke er nåbare slått på, lister den også hvilke funn som ikke blokkerte, og hvorfor.

Måle dekningen

Andelen av de åpne avhengighetsfunnene dine som har en vurdering, og andelen som ikke er nåbare, per økosystem og over 30 eller 90 dager, finner du på siden for utbedringsmålinger.

Hva statisk analyse ikke kan se

En manglende kallsti er sterke bevis, ikke et bevis i streng forstand. Ingen av motorene ser kode som nås via refleksjon, plugins, unsafe, eval, avhengighetsinjeksjon eller generert kode, eller kode utenfor det som ble analysert: et separat CLI, et delt bibliotek, eller for Go alt utenfor binærfilen. Et sårbarhetsvarsel kan også navngi feil funksjoner.

For Go i kildemodus dekker kallgrafen main-pakkene og de eksporterte funksjonene dine slik de bygges for Linux på amd64 uten cgo. Kall via grensesnittverdier og funksjonsverdier følges. Kall via refleksjon, og kall som bare finnes i filer for andre plattformer eller i cgo-filer, følges ikke, og derfor blir de funnene unknown (reflection, build_constraints) i stedet for not reachable.

For JavaScript og TypeScript er kallgrafen omtrentlig. Jelly er en analysator på forskningsnivå, og en dynamisk require eller import() stopper enhver unreachable-vurdering for repositoryet. En Importert-vurdering sier at pakken lastes. Den sier ikke at den sårbare koden kjører.

For Python og for Java og Kotlin følges importer gjennom andre pakker (se over). For Python fungerer dette bare så langt koden deres navngir en modul bokstavelig. For Java og Kotlin fungerer det bare så langt de kompilerte klassene deres navngir en klasse. En pakke som laster moduler eller klasser med beregnede navn, ServiceLoader eller refleksjon, følges ikke forbi det punktet. Rammeverk som laster klasser fra konfigurasjon, som JDBC-drivere og avhengighetsinjeksjon, ses heller ikke. En Java- eller Kotlin-pakke som bare brukes på den måten, vises som unknown selv om den lastes.

Derfor heter gruppen trolig ikke utnyttbar, og derfor viser hver vurdering motoren, versjonen og databasedatoen: sjekk bevisene før du avviser et funn.

API

Hvert funn fra GET /orgs/{org}/code-security/deps/findings og GET /orgs/{org}/code-security/images/findings har et reachability-objekt. For en Go-binærfil:

"reachability": {
  "verdict": "reachable",
  "level": "function",
  "reason_unknown": null,
  "engine": "govulncheck",
  "engine_version": "v1.8.0",
  "db_version": "2026-10-10T11:47:18Z",
  "advisory_id": "GO-2026-5320",
  "evidence": {
    "binary": "usr/local/bin/app",
    "frames": [{ "module": "github.com/yuin/goldmark", "package": "github.com/yuin/goldmark/renderer/html", "receiver": "Renderer", "function": "renderLink" }]
  },
  "computed_at": "2026-10-12T05:40:00.000Z"
}

For Go i kildemodus går rammene fra inngangspunktet i repositoryet ditt til den berørte funksjonen, gjennom standardbiblioteket og din egen handler (en utplantet test, 2026-10-13):

"reachability": {
  "verdict": "reachable",
  "level": "function",
  "reason_unknown": null,
  "engine": "govulncheck",
  "engine_version": "v1.8.0 (source, go1.27.2)",
  "db_version": "2026-10-10T11:47:18.507452919Z",
  "advisory_id": "GO-2026-6278",
  "evidence": {
    "mode": "source",
    "manifest": "reach-go/a/go.mod",
    "module": "github.com/gorilla/websocket",
    "version": "v1.5.0",
    "symbols": ["github.com/gorilla/websocket.*Upgrader.Upgrade"],
    "frames": [
      { "file": "reach-go/a/main.go", "line": 22, "go_package": "example.com/a", "function": "main" },
      { "file": "src/net/http/server.go", "line": 3604, "package": "stdlib@v1.27.2", "go_package": "net/http", "receiver": "*Server", "function": "Serve" },
      { "file": "src/net/http/server.go", "line": 2358, "package": "stdlib@v1.27.2", "go_package": "net/http", "receiver": "HandlerFunc", "function": "ServeHTTP" },
      { "file": "reach-go/a/main.go", "line": 13, "go_package": "example.com/a", "function": "handler" },
      { "file": "server.go", "line": 125, "package": "github.com/gorilla/websocket@v1.5.0", "go_package": "github.com/gorilla/websocket", "receiver": "*Upgrader", "function": "Upgrade" }
    ]
  },
  "computed_at": "2026-10-13T19:43:52.589Z"
}

En ramme uten package ligger i repositoryet ditt, med en file relativt til repositoryet. En ramme med package ligger i en avhengighet eller i standardbiblioteket, og file er relativ til den modulen. Høyst 8 rammer beholdes: inngangspunktet, deretter de siste 7 ned til den berørte funksjonen (eksemplet over utelater 3 rammer fra standardbiblioteket).

For en npm-pakke som koden din laster gjennom en annen pakke:

"reachability": {
  "verdict": "reachable",
  "level": "import",
  "reason_unknown": null,
  "engine": "jelly",
  "engine_version": "0.13.0",
  "db_version": "2026-10-12T02:00:00.000Z",
  "advisory_id": "GHSA-pxg6-pf52-xh8x",
  "evidence": {
    "manifest": "package-lock.json",
    "package": "cookie",
    "version": "0.6.0",
    "frames": [
      { "file": "src/server.ts", "line": 3 },
      { "file": "index.js", "line": 9, "package": "express@4.21.0" },
      { "file": "index.js", "line": 1, "package": "cookie@0.6.0" }
    ]
  },
  "computed_at": "2026-10-12T09:15:00.000Z"
}

For en Python-pakke som koden din importerer:

"reachability": {
  "verdict": "reachable",
  "level": "import",
  "reason_unknown": null,
  "engine": "python-imports",
  "engine_version": "1.1.0 (python 3.13.5)",
  "db_version": "2026-10-12T02:00:00.000Z",
  "advisory_id": "GHSA-9hjg-9r4m-mvj7",
  "evidence": {
    "manifest": "requirements.txt",
    "package": "requests",
    "version": "2.31.0",
    "mapping": "wheel requests-2.31.0-py3-none-any.whl",
    "provides": ["requests"],
    "frames": [{ "file": "app/main.py", "line": 2 }]
  },
  "computed_at": "2026-10-12T15:00:00.000Z"
}

For en Python-pakke som bare lastes gjennom en annen pakke, er frames stien, som for npm, og via navngir pakkene på den:

"evidence": {
  "manifest": "requirements.txt",
  "package": "idna",
  "version": "3.6",
  "mapping": "wheel idna-3.6-py3-none-any.whl",
  "provides": ["idna"],
  "via": ["requests@2.32.3"],
  "frames": [
    { "file": "app/main.py", "line": 2 },
    { "file": "requests/models.py", "line": 401, "package": "requests@2.32.3" }
  ]
}

Maven-vurderinger har samme form, med engine jvm-imports, mapping som navngir JAR-filen og provides som lister Java-pakkene i den. Gjennom en annen pakke navngir en ramme inne i en JAR kildefilen fra klassens feilsøkingsinformasjon og linjen der den neste pakkens klasse brukes. Linjen er 0 når ingen instruksjon bruker den, som for et implementert grensesnitt:

"evidence": {
  "manifest": "pom.xml",
  "package": "org.apache.commons:commons-text",
  "version": "1.9",
  "mapping": "jar commons-text-1.9.jar",
  "via": ["org.apache.commons:commons-configuration2@2.7"],
  "frames": [
    { "file": "src/main/java/app/App.java", "line": 3 },
    { "file": "org/apache/commons/configuration2/PropertiesConfiguration.java", "line": 1663, "package": "org.apache.commons:commons-configuration2@2.7" }
  ]
}

For en Python-utgivelse med bare sdist navngir mapping sdist-filen og hvordan navnene ble funnet, for eksempel sdist pysaml2-4.4.0.tar.gz, package directories under src/.

Den første npm-rammen er linjen i repositoryet ditt. Rammene etter den er filer og linjer inne i pakkene på veien, hver navngitt med versjonen sin.

Et funn i en pull request har også block_waived: "unreachable" når policyen om ikke å blokkere på funn som ikke er nåbare slapp det gjennom fremforge/dep-scan ved siste skanning, ellers null. Det er ikke en avvisning.

Selve policyen leses i dep_scan_unreachable_policy på GET /orgs/{org}/security og settes med PUT /orgs/{org}/security/dep-scan-unreachable-policy (scope policy:write):

{ "enabled": true, "repos": ["web", "acme/api"] }

enabled er påkrevd. repos tar navn på organisasjonens repositoryer, alene eller som org/name; utelat det, eller send [], for alle repositoryer. Svaret inneholder den lagrede policyen, den forrige og om den endret seg.

Legg til ?reachability=reachable, unreachable eller unknown for å liste bare de funnene. De tre verdiene deler listen uten overlapp. Uten parameteren returneres alle funn. Bevisene inneholder bare kodeplasseringer, aldri kodeinnhold.

Legg til ?sort=risk for å liste funnene i triagerekkefølge: vurdering (nåbar, deretter ukjent eller ikke analysert, deretter ikke nåbar), deretter alvorlighetsgrad, deretter kjent utnyttet (avhengighets- og imagefunn), deretter EPSS for avhengighetsfunn, deretter eldste først. Paginering med offset er stabil i denne rekkefølgen. Uten parameteren, eller med sort=created, listes funnene med de nyeste først, som før.

Hvert SAST-funn fra GET /orgs/{org}/code-security/sast/findings har triagesignalene sine:

"triage": {
  "confidence": "lower",
  "reasons": ["test"],
  "location": "test",
  "dataflow": true,
  "dismissed_before": { "repo": 0, "org": 1, "days": 90 }
}

dataflow er true for et taint-treff, false for et treff som bare bygger på mønster, og null for et funn som ble opprettet før signalet fantes. Neste skanning av repositoryet fyller det inn.