Hoppa till huvudinnehållet

Nåbarhet

Ett säkerhetsmeddelande för ett beroende säger att en paketversion är sårbar. Det säger inte om ditt program kan nå den sårbara koden. Nåbarhetsanalysen svarar på det för Go, utifrån de binärfiler du faktiskt levererar, och utifrån ditt repos kod för JavaScript och TypeScript (npm) och, på importnivå, Python (PyPI) samt Java och Kotlin (Maven). Den visar dig varför. För Go analyserar den även ditt repos egen kod (källkodsläge); se nedan.

Vad den kontrollerar

Go: binärfilerna du levererar

När fremforge skannar om container-images i din organisations registry läses varje Go-binärfil som har ett sårbarhetsfynd av govulncheck i binärläge. govulncheck läser binärfilens modullista och symboltabell och jämför dem med Gos sårbarhetsdatabas, som anger exakt vilka funktioner varje säkerhetsmeddelande berör.

  • Ingenting i din image byggs eller körs. Binärfilen läses som en fil.
  • Ingen tjänst anropas. Sårbarhetsdatabasen är fremforges egen kopia av OSV:s Go-poster och uppdateras dagligen.
  • govulncheck (BSD-3-Clause) är låst till en release och uppdateras via Renovate.

Terraform- och OpenTofu-providers: binärfilerna dina låsfiler låser

Ett fynd i en Terraform- eller OpenTofu-provider är en Go-modul som är inbyggd i den provider-binärfil som din .terraform.lock.hcl låser. fremforge läser den binärfilen med govulncheck i binärläge, som för en Go-binärfil i en image, och fyndet får bedömningen nåbar när en berörd funktion är länkad i providern, och inte nåbar när modulen (eller dess paket) finns i binärfilen men ingen av de funktioner som säkerhetsmeddelandet nämner gör det.

  • Provider-releaser byggs utan symboltabell (-ldflags=-s). Den funktionstabell som Go behåller vid körning finns ändå kvar; fremforge återställer den enda symbol som govulncheck behöver för att läsa den, och resultatet blir detsamma som för samma provider byggd med sina symboler. Om symbolen inte kan hittas förblir bedömningen unknown (no_symbol_table).
  • Varje provider-version analyseras en gång, för alla organisationer som låser den, från den kopia som fremforges provider-spegel har. Ingenting om ditt repo används.
  • En provider-binärfil över 512 MiB (till exempel hashicorp/aws) behåller bedömningen unknown (engine_failed).

Go: ditt repos kod

När en beroendeskanning hittar sårbara Go-moduler kör fremforge även govulncheck i källkodsläge på den skannade commiten. Den typkontrollerar dina moduler och bygger en anropsgraf från dina main-paket, så att den kan visa anropsvägen från en rad i ditt repo till den berörda funktionen, även när ingen image har byggts från den commiten.

Det kräver kommandot go, som ett repo kan försöka styra. fremforge kör det så att ingenting från ditt repo körs och ingenting hämtas annat än via din organisations beroendeproxy. Designen granskades innan den släpptes.

  • Ingenting i ditt repo körs. Ingen go generate, inga tester, inget bygge, ingen cgo (CGO_ENABLED=0), ingen -toolexec. Bara Go-verktygskedjans egen typkontroll läser din kod.
  • Ingen annan verktygskedja. En toolchain-rad ignoreras (GOTOOLCHAIN=local). En go-rad som är nyare än fremforges Go gör modulen unknown (build_failed). fremforge håller sin Go aktuell via Renovate.
  • Ingen versionshantering och inget annat nätverk. Moduler kommer bara från din organisations beroendeproxy, via ett relä som lägger till fremforges inloggningsuppgift för skanning, så din paketpolicy gäller. Det finns ingen reserväg till en värd för versionshantering. Om din organisation har stängt av sin beroendeproxy läser skanningen i stället moduler från fremforges egen skanningscache på samma proxy. Den cachen innehåller bara publika moduler från proxy.golang.org, var och en kontrollerad mot sum.golang.org, och använder ingen av dina inloggningsuppgifter, så din paketpolicy gäller inte för de läsningarna. En organisation vars proxy avvisar en modul enligt sin policy får unknown för den; skanningen går aldrig runt din proxy.
  • Privata moduler begärs aldrig. En modul under frem.sh, eller som matchar ett GOPRIVATE-, GONOPROXY- eller GONOSUMDB-mönster som ditt repo deklarerar (i sina CI-arbetsflöden, go.env, .envrc, .env eller Makefile), avvisas innan någon begäran lämnar skanningen. Dess sökväg skickas aldrig till beroendeproxyn, till proxy.golang.org eller till sum.golang.org, och allt som behöver den blir unknown (build_failed). Samma regel gäller för uppslagningarna av licens, releaseålder och beroendegraf för Go. Se vad som når Google för publika moduler.
  • Dina inställningsfiler läses inte. En incheckad GOFLAGS-fil, go.env eller .config/go/env, en vendor/-katalog och en .netrc ignoreras. Symboliska länkar följs inte.
  • Avvisas före analysen, som unknown (build_failed): en modul som styrs av en go.work (den ändrar vilken kod som byggs), en replace till en absolut sökväg eller utanför repot, och en modulsökväg som direkt anger ett versionshanteringsrepo (….git).
  • Åtskild från fremforges inloggningsuppgifter. Analysen körs i en egen container som inte har några inloggningsuppgifter och inte når något annat än reläet. Den har egna gränser för minne och CPU.
  • Gränser: 20 moduler, 20 000 filer och 128 MiB av ditt repo per skanning, 512 MiB modulnedladdningar och en tidsbudget på 3 minuter per skanning. Över en gräns blir det unknown.
  • Tester (_test.go) analyseras inte, precis som i binärläge. Standardbiblioteket bedöms bara i binärläge: källkodsläget skulle läsa det i fremforges Go-version, inte i din.
  • Den underkänner aldrig skanningen och ändrar aldrig statusen fremforge/dep-scan.

JavaScript och TypeScript: ditt repos kod

När en beroendeskanning hittar sårbara npm-paket kör fremforge Jelly, en statisk anropsgrafsanalysator för JavaScript och TypeScript från Aarhus universitet, på den skannade commiten. Den kontrollerar om din kod läser in det sårbara paketet, direkt eller via andra paket.

  • Jelly läser din kod. Den kör den aldrig: ingenting installeras, ingen paketkod körs och inget installationsskript körs.

  • Paketen på vägen till ett sårbart paket hämtas efter namn och version och packas upp som data. Vart och ett kontrolleras mot integritetshashen i din låsfil, och ditt repos .npmrc används inte. De kommer via din organisations beroendeproxy (se Varifrån paketfilerna kommer).

  • Varje tarball läses som en ström. Den kontrolleras mot sin integritetshash medan den kommer in, och bara de filer som Jelly läser skrivs: .js, .mjs, .cjs, .jsx, .ts, .mts, .cts, .tsx och .json. Native-binärfiler och andra stora filer hoppas över utan att sparas, så ett paket som onnxruntime-node (108 MiB) analyseras som vilket annat som helst. Filer behålls bara när hashen stämmer.

  • Gränser: en tarball på upp till 512 MiB, 2 GiB uppackad, 100 000 poster, 10 000 skrivna filer och 16 MiB per skriven fil. Alla paket som läggs ut för en låsfil kan ta upp till 96 MiB skrivna filer. Ett paket över en gräns gör de fynd som behöver det unknown (build_failed). En fil som hoppats över på grund av sin storlek låter aldrig ett fynd bli unreachable.

  • Låsfiler som stöds:

    LåsfilVersionerIntegriteten kontrolleras mot
    package-lock.json, npm-shrinkwrap.jsonlåsfilsversion 2 eller 3 (npm 7 och senare)låsfilen
    pnpm-lock.yaml5.x, 6 och 9låsfilen
    yarn.lock, classicyarn 1låsfilen (integrity, eller SHA-1 i en äldre resolved-URL)
    yarn.lock, berryyarn 2 och senare (__metadata version 4 och senare)den integritet som ditt registry publicerar för den versionen, eftersom berrys checksum täcker yarns eget cachearkiv och inte npm-tarballen. Ett paket vars publicerade integritet inte kan läsas hämtas inte.
    bun.locktextformat (bun 1.2 och senare)låsfilen

    För yarn classic, som inte registrerar några workspaces, läses också package.json bredvid låsfilen och dess workspaces. bun.lockb, buns äldre binära format, läses inte: det är en odokumenterad minnesavbild som har ändrats mellan bun-versioner. Dess fynd blir unknown, och belägget säger varför. Andra låsfiler ger unknown.

  • Jelly (BSD-3-Clause) körs inne i fremforges skanningsjobb och anropar ingen tjänst. Den är låst till en release och uppdateras via Renovate.

  • Analysen har en tidsbudget på 2 minuter per skanning. Den underkänner aldrig skanningen. Den ändrar statusen fremforge/dep-scan bara om din organisation väljer att inte blockera på fynd som inte är nåbara.

Python, Java och Kotlin: ditt repos importer

När en beroendeskanning hittar sårbara PyPI- eller Maven-paket kontrollerar fremforge om din kod importerar dem. Det här sker bara på importnivå: det säger dig att ett paket läses in, aldrig att den sårbara koden körs, och det ger aldrig unreachable.

  • Python. Dina .py-filer parsas med Pythons egen ast-modul, som bara parsar. Ingenting importeras eller körs. fremforge läser import- och from … import-satser samt anrop av importlib.import_module(...) och __import__(...) med ett literalt namn. En fil som inte går att parsa med aktuell Python, till exempel Python 2-kod, läses i stället rad för rad efter sina importsatser. Relativa importer (from . import x) är dina egna moduler och hoppas över, liksom virtuella miljöer (.venv, venv, site-packages) och symboliska länkar.

  • Python, via andra paket. När din kod inte själv importerar ett sårbart paket följer fremforge de paket som din kod importerar: den läser deras kod från deras wheels på samma sätt, med start i de moduler som din kod importerar, och följer bara deras egna importer. Om kod som nås på det sättet importerar det sårbara paketet blir fyndet Importerad, och dess belägg visar vägen: din import, sedan importen inne i varje paket, till exempel idna via requests. En modul som ingenting läser in (som ett pakets help.py) och importer under if TYPE_CHECKING: följs inte. Den här genomgången går högst tre paket djupt och läser högst 40 wheels på upp till 16 MiB vardera per skanning. Den lägger bara till bedömningar av typen Importerad; en väg som den inte kan följa lämnar fyndet unknown.

  • Java, Kotlin, Groovy och Scala. fremforge läser import-satser, fullständigt kvalificerade klassnamn i kod samt Class.forName("…") och loadClass("…") med ett literalt namn. Kommentarer och strängliteraler ignoreras, och det gör även build/ och target/. Ingenting kompileras.

  • Java och Kotlin, via andra paket. När din kod inte själv importerar ett sårbart Maven-paket följer fremforge de paket som din kod importerar, i deras kompilerade klasser. Den börjar i de klasser som din kod importerar (varje klass i paketet för en jokerteckenimport import a.b.*). Därifrån följer den de klasser som de använder: varje klass som en metod anropar, skapar, typomvandlar till eller läser ett fält i, och varje superklass och gränssnitt. Dessa läses från varje klassfils konstantpool. Om en klass som nås på det sättet använder en klass i det sårbara paketet blir fyndet Importerad. Dess belägg visar vägen: din import, sedan källfilen och raden inne i varje paket där nästa paket används. Ett exempel är commons-text via commons-configuration2. En klass som ingenting når följs inte, och inte heller en klass som läses in efter namn från en sträng. Klassfiler läses som data: ingen klass läses in eller körs, och ingen JVM är inblandad. Den här genomgången går högst tre paket djupt och läser högst 40 JAR-filer på upp till 32 MiB vardera per skanning, en i taget. Den lägger bara till bedömningar av typen Importerad; en väg som den inte kan följa lämnar fyndet unknown.

  • Vilka namn ett paket tillhandahåller hämtas från fillistan i dess publicerade arkiv, som läses som data:

    • PyPI: wheel-filen för den versionen. Ett namespace-paket löses upp till sitt första verkliga paket, till exempel google.protobuf för protobuf.
    • PyPI, en release utan wheel (bara sdist): källarkivet, som läses som data och aldrig installeras. setup.py varken körs eller läses. Namnen hämtas från paketlistorna i setup.cfg eller pyproject.toml (setuptools, hatch, flit och poetry), annars från de kataloger som innehåller en __init__.py, på toppnivå, under src/ eller under en katalog som lib/. Så pysaml2 tillhandahåller saml2 och pycrypto tillhandahåller Crypto. PKG-INFO måste ange samma projekt. Arkiv på upp till 16 MiB läses (.tar.gz, .tar, .zip). En release som inte finns i något index, eller en sdist som inte anger något namn (till exempel en .tar.bz2), faller tillbaka på projektnamnet, så requests står för import requests; belägget anger det i mapping.
    • Maven: JAR-filen på Maven Central, och de Java-paket som dess klasser ligger i.

    För en wheel eller JAR hämtas bara arkivets katalog, med HTTP range-förfrågningar, så en stor fil kostar några kilobyte. Genomgången via andra paket läser hela wheel- eller JAR-filen för varje paket den följer, och en sdist läses alltid i sin helhet. Ingenting installeras, byggs eller körs.

  • Ditt repo byggs inte. Nåbarhet för Java med anropsgrafer, som osv-scanners experimentella JAR-analys eller jdeps, kräver en byggd JAR. En skanning av en pull request bygger inte ditt projekt, så de verktygen används inte.

  • Analysen har en tidsbudget på 1 minut per ekosystem och skanning, och körs parallellt med npm-analysen. Den underkänner aldrig skanningen och ändrar aldrig statusen fremforge/dep-scan.

Varifrån paketfilerna kommer

npm-tarballer, PyPI-index och wheels samt Maven-JAR:er läses via din organisations beroendeproxy, på en intern väg som bara fremforges skanningstjänst kan nå. Så din organisations paketpolicy, cache, lagringstak och uppströmsgräns gäller för dem som för vilken annan hämtning som helst, och det som skanningen hämtar cachas för dina byggen.

  • Om din policy avvisar ett paket (till exempel skadlig kod, en för ny release eller en licensregel) hämtar skanningen det inte någon annanstans. De fynd som behöver det blir unknown (build_failed), och belägget anger proxyns beslut.
  • Om din organisation har stängt av beroendeproxyn, eller om proxyn inte kan svara, läses filerna i stället från de publika registren (npmjs, PyPI, Maven Central), som tidigare.
  • Filer som skanningen hämtar räknas in i din organisations lagring i proxyn, som alla andra cachade filer.

Nivåerna

En bedömning har en nivå: hur mycket motorn kunde se.

NivåBetydelse
functionSäkerhetsmeddelandet anger de berörda funktionerna, och motorn letade efter en väg till dem. Det är vad govulncheck ger för Go.
importSäkerhetsmeddelandet anger inga berörda funktioner. Motorn kan bara säga om det sårbara paketet läses in.

npm-säkerhetsmeddelanden anger nästan aldrig berörda funktioner. När detta mättes den 12 oktober 2026 gjorde ingen av de 230 287 npm-posterna i OSV-databasen det. Därför är bedömningar för JavaScript och TypeScript på importnivå: de säger att din kod läser in det sårbara paketet, inte att den anropar den sårbara koden. Om ett npm-säkerhetsmeddelande anger berörda funktioner kontrollerar Jelly dem på funktionsnivå.

Bedömningar för Python och Maven är alltid på importnivå. Samma mätning hittade data om berörda funktioner i 2 av 26 221 PyPI-poster och i ingen av de 7 190 Maven-posterna.

De tre bedömningarna

Varje fynd för beroenden och images har en av dessa:

BedömningGo (govulncheck)JavaScript och TypeScript (Jelly)Python, Java och Kotlin (importnivå)
NåbarEn berörd funktion är länkad i binärfilen. Go-länkaren tar bort kod som ingenting kan anropa, så en länkad funktion är en som ditt program kan nå. Markeringen anger funktionen, till exempel html.Renderer.renderLink. I källkodsläge: en anropsväg från din kod når en berörd funktion; markeringen anger fil och rad för det sista anropet i ditt repo innan vägen går in i beroendet, till exempel din handler snarare än main. Hela vägen finns i belägget.Importnivå, visas som Importerad: din kod läser in paketet i den sårbara versionen, direkt eller via andra paket. Funktionsnivå, visas som Nåbar: ett anrop i din kod kan nå en berörd funktion. Markeringen anger fil och rad i ditt repo, till exempel src/session.ts:12.Visas som Importerad: din kod importerar en modul eller ett Java-paket som det sårbara paketet tillhandahåller. Markeringen anger fil och rad för importen, till exempel app/main.py:2.
Ej nåbar (unreachable)Modulen finns i binärfilen i en berörd version, säkerhetsmeddelandet anger de berörda funktionerna, govulncheck körde klart och ingen av de funktionerna finns i binärfilen. I källkodsläge: modulen används i en berörd version, govulncheck hittade ingen anropsväg till någon berörd funktion och ingenting som govulncheck inte kan följa (reflektion, filer för andra plattformar, cgo, plugins) finns i din kod.Säkerhetsmeddelandet anger de berörda funktionerna, Jelly körde klart med varje paket på vägen tillgängligt och inget anrop i din kod når någon av dem. Utan den funktionsdatan blir ett paket som din kod aldrig läser in unknown, inte unreachable.Aldrig. Importer inne i andra paket följs bara så långt som de anger en modul eller klass literalt, så ett paket som din kod inte verkar läsa in kan ändå läsas in.
OkändAllt annat. Det är standardläget, och det behandlas aldrig som säkert.Samma sak.Samma sak, inklusive varje paket som din kod inte importerar.

unreachable kräver att alla villkor är uppfyllda. En indata som saknas ger alltid unknown, med orsaken:

OrsakVarför
no_symbol_dataSäkerhetsmeddelandet anger inte de berörda funktionerna, så att en väg saknas bevisar ingenting. För npm är detta den vanliga orsaken när din kod inte läser in paketet. För Python och Maven är det orsaken så fort din kod inte importerar paketet.
no_symbol_tableGo: binärfilen byggdes med -ldflags=-s. Dess symboler kan inte läsas, så ingen av bedömningarna kan ges. Bygg utan -s (att behålla -w går bra) för att få bedömningar. Terraform-providers: den symbol som fremforge återställer kunde inte hittas i den här binärfilen.
build_failedGo i källkodsläge: modulen avvisades före analysen (se ovan), kunde inte läsas in, eller så kunde en modul inte hämtas från din beroendeproxy. npm: låsfilen har inte något av de format som stöds, eller så kunde ett paket på vägen inte hämtas, var över en gräns eller matchade inte sin integritetshash. Python och Maven: wheel-, sdist- eller JAR-filen kunde inte läsas, till exempel en artefakt med bara POM eller en som inte finns på Maven Central.
dynamic_codeDin kod läser in moduler eller klasser efter beräknade namn, så att en anropsväg eller import saknas bevisar ingenting. npm: require(name) och import(name). Python: importlib.import_module(name) och __import__(name). Java: Class.forName(name) och loadClass(name). Go i källkodsläge: paketet plugin eller //go:linkname.
reflectionGo i källkodsläge: din kod anropar metoder via reflect (MethodByName, Method, Call), eller använder text/template eller html/template när säkerhetsmeddelandet anger metoder. govulncheck kan inte följa de anropen, så att en anropsväg saknas bevisar ingenting.
build_constraintsGo i källkodsläge: en fil som analysen inte läste in importerar andra paket. Analysen läser in din kod som för Linux på amd64 utan cgo, så en _windows.go-fil, en fil vars //go:build-rad utesluter Linux eller en cgo-fil finns inte i anropsgrafen, och ett anrop som bara görs där skulle missas. Ett paket som bara byggs med cgo (till exempel ett skrivbordsgränssnitt på ett verktygspaket som kräver cgo) lämnas utanför analysen i stället för att få den att misslyckas: resten av modulen analyseras, och varje modul som det paketet importerar får den här orsaken i stället för unreachable.
timeoutAnalysen överskred sin tidsbudget (5 minuter per image för Go, 2 minuter per skanning för npm, 1 minut per ekosystem och skanning för Python och Maven).
engine_no_matchGo: govulncheck rapporterade inte den här modulversionen som berörd av säkerhetsmeddelandet, trots att image-skannern gjorde det. Ingen av dem litas på mer än den andra.
oom_killedGo i källkodsläge: analysen fick slut på minne och stoppades, så ingenting avgjordes.
engine_failedAnalysen kunde inte köras på den här binärfilen eller det här repot.
not_analysedIngen bedömning har beräknats: fyndet har inte skannats sedan nåbarhet lades till, eller så har ett Go-fynd ingen image byggd från sin commit.
unsupported_ecosystemEtt beroendefynd utanför Go, npm, PyPI, Maven och Terraform-providers, till exempel NuGet eller Cargo.

Beroendefynd

Go. Ett beroendefynd för Go får sin bedömning i binärläge, från en image byggd från exakt den commiten. Där källkodsläget är påslaget (än så länge fremforges interna organisationer) får det även en vid varje skanning, med anropsvägen i ditt repo. Märk dina images med de två standardetiketterna för OCI:

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

docker/metadata-action sätter båda. Bedömningen gäller bara den commit som imagen anger och de modulversioner som binärfilerna byggdes med. Om någon Go-binärfil i den imagen inte kunde läsas förblir beroendefyndet unknown. Om flera binärfiler innehåller modulen är fyndet nåbart när någon av dem når den.

När båda lägena bedömer samma fynd vid samma commit raderar inget av dem det andra: en unknown från det ena ersätter aldrig en bedömning från det andra, och ej nåbar från det ena ersätter aldrig nåbar från det andra. Belägg från källkodsläget har "mode": "source".

npm, PyPI och Maven. Bedömningarna kommer med själva beroendeskanningen: varje skanning av en pull request, och skanningen av din standardbranch efter varje push (högst en gång i timmen). En bedömning hör alltid till den commit som skannades. Om samma paket och säkerhetsmeddelande förekommer i flera låsfiler är fyndet nåbart när någon av dem når det.

Hur fremforge använder den

Rangordning. Fyndlistorna Beroenden och Container-images sorteras med nåbara först, sedan okända, sedan ej nåbara. Inom varje grupp sorteras de efter allvarlighetsgrad, sedan kända som utnyttjade före resten, sedan efter EPSS. Ett fynd är känt som utnyttjat när något av dess CVE-id:n, dess egna eller säkerhetsmeddelandets alias, listas som utnyttjat av ENISA:s EU Vulnerability Database eller av CISA:s katalog Known Exploited Vulnerabilities. Båda listorna visar en etikett Känd som utnyttjad vars verktygstips anger källan: EU (ENISA EUVD), US (CISA KEV) eller båda, och ovanför varje lista visar Endast kända som utnyttjade bara de fynden (fynd-API:ts ?known_exploited=true). Båda listorna uppdateras dagligen. Ett Importerad-fynd rangordnas med de nåbara. Samma ordning används av:

  • fliken Rekommendationer, där ett kort (en uppgradering av ett paket i ett repo) tar den mest nåbara bedömningen av de fynd det åtgärdar och märks Nåbar eller Ej nåbar;
  • den veckovisa sammanställningens Top fixable today, som visar varje rads bedömning;
  • fynd-API:t med ?sort=risk.

Aviseringar. När ett öppet beroendefynd blir nåbart, eller blir känt som utnyttjat, får din SIEM en granskningshändelse direkt och organisationens säkerhetskontakter får ett mejl, en gång per fynd: se Aviseringar om fynd. Kända som utnyttjade, och nåbara med allvarlighetsgrad HIGH eller CRITICAL, mejlas direkt. Nåbara med allvarlighetsgrad MEDIUM eller LOW hamnar i varje persons dagliga sammanfattning av aviseringar, eller skickas direkt till den som har stängt av sammanfattningen. Checklistan för att komma igång under Säkerhet › Översikt visar vilka av dina images som har Go-binärfiler utan symboler.

Gruppen troligen inte utnyttjbara. Fynd som inte är nåbara flyttas till en hopfälld grupp längst ned i listan, med antalet i rubriken. De förblir synliga, valbara och möjliga att avfärda, och de räknas in i varje summa.

Ingenting döljs eller avfärdas. En bedömning skriver aldrig ett avfärdande. Den ändrar ett fynds SLA bara när din organisation väljer att använda SLA-multiplikatorn. Som standard läser commit-statusen (fremforge/dep-scan, fremforge/image-scan) inte bedömningar: det som blockerar en merge eller en pull är oförändrat. Det enda undantaget är den valfria policyn att inte blockera pull requests på fynd som inte är nåbara, som bara gäller fremforge/dep-scan.

SLA-multiplikator (valfri)

En ägare av organisationen kan förlänga SLA:n per allvarlighetsgrad för fynd som inte är nåbara, under Säkerhet › Prioritera › Åtgärdsfrist (SLA) (/<org>/_admin/security/prioritise/sla), eller med unreachable_sla_multiplier på PUT /orgs/{org}/security/sla-policy. Värdet är ett heltal från 1 till 4. Standardvärdet, 1, betyder avstängd.

  • Bara unreachable-fynd förlängs. Nåbara och okända fynd behåller alltid hela SLA:n, och det gör även ett fynd som inte har analyserats.
  • Ett fynd som är känt som utnyttjat (listat av EU (ENISA EUVD) eller US (CISA KEV), se Rangordning ovan) förlängs aldrig, oavsett allvarlighetsgrad och bedömning.
  • Ett kritiskt fynd vars EPSS-poäng ligger bland de översta 10 % (percentil 0,90 eller mer) förlängs aldrig, oavsett bedömning.
  • Tidsfristen räknas alltid från när fyndet först sågs. När en senare skanning hittar en anropsväg, eller inte kan avgöra, gäller hela SLA:n direkt igen, så fyndet kan gå direkt till över SLA. SLA-markeringen säger då varför.
  • Med multiplikatorn påslagen visar en förlängd SLA-markering ett litet ×2 (eller ×3, ×4) och ett verktygstips med båda tidsfristerna. Den veckovisa sammanställningens antal över SLA, översiktspanelen och SIEM-händelsen code-security.sla.breached använder samma förlängda tidsfrister.
  • Multiplikatorn ändrar bara tidsfrister. Den ändrar inte vad som blockerar en pull request, och den döljer ingenting.

Varje ändring granskningsloggas som code-security.sla_policy.updated, med det tidigare värdet.

Blockera inte på fynd som inte är nåbara (valfritt)

Som standard blockerar varje beroendefynd på eller över din blockeringsgräns pull requesten, oavsett bedömning. En ägare av organisationen kan välja att ett fynd med ej nåbar inte blockerar fremforge/dep-scan. Det är avstängt tills du slår på det.

Risken. En saknad anropsväg är starkt belägg, inte bevis (se Vad statisk analys inte kan se). Om analysen missar en väg genom reflektion, en plugin, en dynamisk import, beroendeinjektion eller kod utanför repot, eller om säkerhetsmeddelandet anger fel funktioner, låter en felaktig ej nåbar en verklig, nåbar sårbarhet mergas. Slå bara på det här där du accepterar det, och överväg att begränsa det till de repon där du litar på analysen.

Slå på det under Säkerhet › Prioritera › Pull request-kontroller (/<org>/_admin/security/prioritise/pr-checks), eller med PUT /orgs/{org}/security/dep-scan-unreachable-policy (se API). Du kan begränsa det till en lista med repon; en tom lista betyder alla repon i organisationen.

Vad det ändrar, och vad det aldrig ändrar:

  • Bara unreachable med belägg räknas. Fyndets bedömning för pull requestens head-commit måste vara ej nåbar, beräknad av en motor med dess version och de berörda funktioner i säkerhetsmeddelandet som den kontrollerade. I dag betyder det Go samt JavaScript och TypeScript. För Go ger govulncheck bedömningen i binärläge när en image byggd från pull requestens head-commit har skannats; en bedömning som kommer efter skanningen gäller från pull requestens nästa skanning. Där källkodsläget är påslaget (än så länge fremforges interna organisationer) ger den också en vid själva skanningen av pull requesten. För JavaScript och TypeScript ger Jelly den när säkerhetsmeddelandet anger berörda funktioner. Bedömningar för Python, Java och Kotlin är på importnivå och är aldrig unreachable, så de blockerar alltid.
  • unknown blockerar alltid. Det finns inget val för att inte blockera på unknown, och ett fynd som inte har analyserats är unknown.
  • Skadlig kod och kända utnyttjade sårbarheter blockerar alltid, oavsett bedömning: ett MAL--säkerhetsmeddelande eller ett säkerhetsmeddelande som är märkt som skadligt, och en sårbarhet där något av CVE-id:na listas som utnyttjat av EU (ENISA EUVD) eller US (CISA KEV). Om fremforge inte kan läsa de uppgifterna under en skanning släpps ingenting igenom i den skanningen.
  • Ingenting döljs. Fyndet sparas, listas, räknas in i varje summa och aviseras som alla andra. Det avfärdas inte, och dess SLA är oförändrad (om inte SLA-multiplikatorn också är påslagen).
  • Bara pull requests. Skanningen av din standardbranch registreras precis som tidigare.
  • Träffar i spärrlistan och blockeringsgränsen är oförändrade. Ett fynd under gränsen blockerade aldrig, och en spärrad komponent blockerar fortfarande.

Blockeringen kommer tillbaka. När en senare skanning av pull requesten hittar en anropsväg, eller inte kan avgöra, blockerar fyndet igen. En bedömning som beräknas utanför en skanning (govulncheck på en image) och att policyn stängs av eller begränsas fångas upp inom en timme: fremforge kontrollerar om varje pull request som gick igenom tack vare policyn och beräknar om dess status, kommentar och granskningshändelse. Samma sak händer när ett fynd blir känt som utnyttjat.

Vad pull requesten visar. Statusen fremforge/dep-scan anger hur många fynd som inte blockerade, till exempel 2 finding(s); 1 at or above critical with no call path, not blocking (org policy). Kommentaren märker varje sådant fynd not blocking och listar dem under Not blocking: no call path (org policy) med motorn, dess version, sårbarhetsdatabasens datum och de funktioner den kontrollerade. Ett fynd utan anropsväg som ändå blockerar listas under Blocking although no call path was found, med orsaken (skadlig kod eller känd som utnyttjad).

Granskning. Varje ändring av policyn granskningsloggas som code-security.deps.unreachable_policy.updated, med det nya och det tidigare värdet, om det ändrades och om ändringen kom från konsolen eller API:t. Varje skanning av en pull request medan policyn gäller registrerar, i sin händelse code-security.dep_scan.ingest, varje fynd som inte blockerade (unreachable_not_blocking, med den motor, version och databasdatum som bedömningen vilade på) och varje fynd som ändå blockerade (unreachable_blocked_anyway, med why). En omkontroll har trigger: unreachable_policy_recheck och orsaken. Båda når dina SIEM-slutpunkter.

När en bedömning ändras: reachability_changed

Ett avfärdande eller ett undantag kan vila på en bedömning. När du avfärdar ett fynd för ett beroende eller en image vars bedömning är ej nåbar, eller begär ett undantag för det, registrerar fremforge den bedömning det vilade på: motorn, dess version, databasens datum och den commit eller image den beräknades på. Panelen för avfärdande säger det.

Varje timme kontrollerar fremforge de avfärdandena och undantagen. När en skanning efter avfärdandet hittar samma fynd som reachable, eller inte kan avgöra (unknown):

  • återkallas ett undantag med orsaken reachability_changed;
  • återkallas ett vanligt avfärdande: fyndet öppnas igen, och ett avfärdande för hela repot som det gjorde slutar gälla för senare skanningar;
  • aviserar fyndet igen via samma säkerhetsavisering som ett utgånget avfärdande;
  • är båda granskningshändelser (code-security.exception.revoked, eller code-security.deps.dismissal_revoked och code-security.images.dismissal_revoked) med den bedömning som låg till grund och den nya, och de når dina SIEM-slutpunkter. Fyndhändelsen säger det också: security.finding.exception_revoked, eller för ett vanligt avfärdande security.finding.dismissal_revoked, båda med transition_reason reachability_changed.

Ett fynd som inte har analyserats igen behåller sitt avfärdande: att en ny skanning saknas är ingen ny bedömning. Ett avfärdande som gjordes medan bedömningen inte var unreachable registrerar ingenting och återkallas aldrig av den här kontrollen, och avfärdanden som gjordes innan detta lades till kontrolleras inte. Om du avfärdade ett fynd av ett skäl som inte beror på nåbarhet, avfärda det igen efter återkallelsen; bedömningen är då inte längre unreachable, så det nya avfärdandet står sig.

Triagesignaler för SAST

SAST-fynd har ingen anropsgraf, så tre deterministiska signaler rangordnar dem i stället. Ingen AI-modell är inblandad.

SignalVad den är
PlaceringUtifrån filsökvägen: testkod (test/, __tests__/, *.test.ts, *_test.go, test_*.py, *Test.java och liknande), exempel och dokumentation, tredjepartskod (vendor/, third_party/, node_modules/) och genererad kod (*.pb.go, *.min.js, gen/, zz_generated* och liknande).
Taint-vägOpenGreps regler i taint-läge spårar data från en källa, som användarindata, till sänkan. En träff med ett spår märks Taint-väg och rangordnas över en träff som bara bygger på mönster. Bara själva faktumet sparas, aldrig spåret.
Ofta avfärdat härPersoner har avfärdat samma regel för minst 2 andra fynd i det här repot, eller 5 i organisationen, under de senaste 90 dagarna. Bottar, automatisk lösning och andra systemaktörer räknas inte.

Ett fynd i test-, exempel-, tredjeparts- eller genererad kod, eller ett som är märkt ofta avfärdat här, flyttas till en hopfälld grupp Lägre tillförlitlighet längst ned i SAST-listan, med antalet i rubriken. En taint-väg flyttar inte ut ett fynd ur den gruppen: en taint-träff i en testfil finns fortfarande i en testfil. Inom varje grupp sorteras fynden efter allvarlighetsgrad, sedan taint-väg, sedan ålder, äldst först.

Precis som gruppen troligen inte utnyttjbara döljs eller avfärdas fynd med lägre tillförlitlighet aldrig: de behåller hela sin SLA, räknas överallt och kan väljas, åtgärdas och avfärdas som alla andra. SAST-fynd-API:t returnerar signalerna som ett triage-objekt på varje fynd, och ?sort=risk listar fynd i den här ordningen över alla sidor.

Kommentar i pull requesten. Kommentaren från beroendeskanningen sorterar fynd på samma sätt och märker vart och ett med dess bedömning när en sådan finns för pull requestens commit: reachable med funktionen eller filen och raden, imported med filen och raden (npm, Python, Java och Kotlin), eller no call path. Med policyn att inte blockera på fynd som inte är nåbara påslagen listar den också vilka fynd som inte blockerade och varför.

Mäta täckningen

Andelen av dina öppna beroendefynd som har en bedömning, och andelen som inte är nåbara, per ekosystem och över 30 eller 90 dagar, finns på sidan Åtgärdsmått.

Vad statisk analys inte kan se

En saknad anropsväg är starkt belägg, inte bevis. Ingen av motorerna ser kod som nås genom reflektion, plugins, unsafe, eval, beroendeinjektion eller genererad kod, eller kod utanför det som analyserades: ett separat CLI, ett delat bibliotek, eller för Go allt utanför binärfilen. Ett säkerhetsmeddelande kan också ange fel funktioner.

För Go i källkodsläge täcker anropsgrafen dina main-paket och exporterade funktioner så som de byggs för Linux på amd64 utan cgo. Anrop via gränssnittsvärden och funktionsvärden följs. Anrop via reflektion, och anrop som bara finns i filer för andra plattformar eller i cgo-filer, följs inte, och därför blir de fynden unknown (reflection, build_constraints) i stället för ej nåbar.

För JavaScript och TypeScript är anropsgrafen ungefärlig. Jelly är en analysator på forskningsnivå, och en dynamisk require eller import() stoppar varje unreachable-bedömning för repot. En Importerad-bedömning säger att paketet läses in. Den säger inte att den sårbara koden körs.

För Python och för Java och Kotlin följs importer via andra paket (se ovan). För Python fungerar det bara så långt som deras kod anger en modul literalt. För Java och Kotlin fungerar det bara så långt som deras kompilerade klasser anger en klass. Ett paket som läser in moduler eller klasser efter beräknade namn, ServiceLoader eller reflektion följs inte förbi den punkten. Ramverk som läser in klasser från konfiguration, som JDBC-drivrutiner och beroendeinjektion, syns inte heller. Ett Java- eller Kotlin-paket som bara används på det sättet visas som unknown trots att det läses in.

Det är därför gruppen kallas troligen inte utnyttjbara, och därför visar varje bedömning motorn, dess version och databasens datum: kontrollera belägget innan du avfärdar ett fynd.

API

Varje fynd från GET /orgs/{org}/code-security/deps/findings och GET /orgs/{org}/code-security/images/findings har ett reachability-objekt. För 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"
}

För Go i källkodsläge går ramarna från ditt repos startpunkt till den berörda funktionen, via standardbiblioteket och din egen handler (ett planterat 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 ram utan package ligger i ditt repo, med en file relativ till repot. En ram med package ligger i ett beroende eller i standardbiblioteket, och dess file är relativ till den modulen. Högst 8 ramar behålls: startpunkten, sedan de sista 7 ned till den berörda funktionen (exemplet ovan utelämnar 3 ramar från standardbiblioteket).

För ett npm-paket som din kod läser in via ett annat paket:

"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"
}

För ett Python-paket som din kod importerar:

"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"
}

För ett Python-paket som bara läses in via ett annat paket är frames vägen, som för npm, och via anger paketen 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-bedömningar har samma form, med engine jvm-imports, mapping som anger JAR-filen och provides som listar dess Java-paket. Via ett annat paket anger en ram inne i en JAR källfilen från klassens felsökningsinformation och raden där nästa pakets klass används. Raden är 0 när ingen instruktion använder den, som för ett implementerat gränssnitt:

"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" }
  ]
}

För en Python-release med bara sdist anger mapping sdist-filen och hur namnen hittades, till exempel sdist pysaml2-4.4.0.tar.gz, package directories under src/.

Den första npm-ramen är raden i ditt repo. Ramarna efter den är filer och rader inne i paketen på vägen, vart och ett med sin version.

Ett fynd i en pull request har också block_waived: "unreachable" när policyn att inte blockera på fynd som inte är nåbara släppte igenom det i fremforge/dep-scan vid dess senaste skanning, annars null. Det är inget avfärdande.

Själva policyn läses i dep_scan_unreachable_policy på GET /orgs/{org}/security och sätts med PUT /orgs/{org}/security/dep-scan-unreachable-policy (scope policy:write):

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

enabled krävs. repos tar namn på din organisations repon, utan prefix eller som org/name; utelämna det, eller skicka [], för alla repon. Svaret innehåller den sparade policyn, den tidigare och om den ändrades.

Lägg till ?reachability=reachable, unreachable eller unknown för att bara lista dem. De tre värdena delar upp listan utan överlapp. Utan parametern returneras alla fynd. Belägg innehåller bara kodplatser, aldrig kodinnehåll.

Lägg till ?sort=risk för att lista fynd i triageordning: bedömning (nåbar, sedan okänd eller inte analyserad, sedan ej nåbar), sedan allvarlighetsgrad, sedan känd som utnyttjad (fynd för beroenden och images), sedan EPSS för beroendefynd, sedan de äldsta först. Sidindelning med offset är stabil i den här ordningen. Utan den, eller med sort=created, listas fynden med de nyaste först, som tidigare.

Varje SAST-fynd från GET /orgs/{org}/code-security/sast/findings har sina triagesignaler:

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

dataflow är true för en taint-träff, false för en träff som bara bygger på mönster och null för ett fynd som togs fram innan signalen fanns. Nästa skanning av repot fyller i den.