123% fler rapporterade CVE:er per dag 2026 än förra året.

Beroenden

Vad är ett transitivt beroende?

Ett transitivt beroende är ett paket som din programvara använder eftersom ett annat paket behöver det. Du har aldrig deklarerat det, men det finns i det du levererar, med egna sårbarheter och en egen licens. Så här ser du dem, åtgärdar dem och bevisar vilka som ingick i varje release.

Uppdaterad

A vulnerable transitive dependency and its fix path An app declares two direct dependencies, express and hbs. Express brings in body-parser and send, which bring in raw-body and mime-types. Hbs brings in handlebars, which is vulnerable. The path from the app through hbs to handlebars is highlighted: upgrade hbs, or override the handlebars version. your project direct transitive, depth 1 depth 2 my-app express hbs body-parser send handlebars vulnerable, required by hbs raw-body mime-types Fix path: upgrade hbs, or override the handlebars version

Direkta och transitiva beroenden

Ett direkt beroende är ett som du deklarerar i ditt manifest. Ett transitivt beroende är ett som dina beroenden deklarerar, och deras beroenden i sin tur, så djupt trädet går. Pakethanteraren löser hela trädet vid installationen och registrerar oftast resultatet i en lockfile.

Ta en app som deklarerar ett enda paket, express. Om du kör npm ls --all ser du vad den enda raden för med sig:

my-app
└─┬ express            ← direkt: du deklarerade det
  ├─┬ body-parser      ← transitivt, djup 1
  │ └── raw-body       ← transitivt, djup 2
  ├── cookie           ← transitivt, djup 1
  └─┬ send             ← transitivt, djup 1
    └── mime-types     ← transitivt, djup 2

Det verkliga trädet är längre. De flesta paketen i en typisk applikation kommer på det här sättet, vilket betyder att det mesta av koden du levererar valdes av pakethanteraren, inte av dig.

Direkt beroende Transitivt beroende
Vem valde det Ditt team, i manifestet Pakethanteraren, utifrån dina beroendens manifest
Var det listas Manifest och lockfile Lockfile, om det finns en
Vem styr versionen Du Föräldrapaketets versionsintervall, om du inte åsidosätter det
Hur du åtgärdar en sårbarhet Uppgradera det Uppgradera föräldern, eller åsidosätt versionen

Varför transitiva beroenden är viktiga

De bär samma risker som direkta beroenden, med mindre insyn och mindre kontroll.

  • Sårbarheter. När Log4Shell, en zero-day i log4j, offentliggjordes fann Googles team Open Source Insights 35 863 artefakter i Maven Central som var beroende av den berörda log4j-koden. Omkring 7 000 var direkt beroende av den. Majoriteten drog in den som ett transitivt beroende, och många kunde inte åtgärdas förrän ett paket däremellan först hade släppt en fix.
  • Attacker mot leveranskedjan. Bakdörren i xz utils (CVE-2024-3094) nådde OpenSSH utan att OpenSSH var beroende av xz. Flera Linux-distributioner patchar OpenSSH för att stödja systemd-notifieringar, och libsystemd är beroende av liblzma, biblioteket som xz tillhandahåller.
  • Licenser. Varje transitivt paket har en egen licens. En copyleft-licens tre nivåer ner är lika bindande som en du lagt till själv.
  • Brytande ändringar. Ett föräldrapaket som accepterar ett versionsintervall släpper in en ny transitiv release vid nästa nya installation, även när inget i ditt manifest har ändrats.

Så listar du dina transitiva beroenden

Alla stora pakethanterare kan skriva ut det upplösta trädet:

Ekosystem Kommando
npmnpm ls --all
pnpmpnpm list --depth Infinity
Python (uv)uv tree
Python (pip)pipdeptree
Gogo mod graph
Rustcargo tree
Mavenmvn dependency:tree
Gradlegradle dependencies

För att ta reda på varför ett enskilt paket finns där kan du fråga efter sökvägen till det: npm explain <package>, pnpm why, yarn why eller cargo tree -i <crate>. För att arbeta med sökvägarna i stället för att skriva ut dem, se beroendegrafer.

Så åtgärdar du ett sårbart transitivt beroende

  1. Uppgradera föräldern. Hitta det direkta beroende som drar in paketet och gå över till en release som kräver en åtgärdad version. Det här är den renaste åtgärden, eftersom förälderns underhållare har testat den.
  2. Uppdatera lockfilen. Om förälderns versionsintervall redan tillåter den åtgärdade versionen räcker det att uppdatera posten i lockfilen, till exempel med cargo update -p <crate> eller en ny npm update.
  3. Åsidosätt versionen. Om föräldern inte har släppt någon fix tvingar du fram versionen själv: overrides i npm och pnpm, resolutions i Yarn, en constraints-fil med pip eller ett högre krav i go.mod. Testa det, eftersom föräldern aldrig släpptes mot den versionen.
  4. Byt ut eller ta bort föräldern. Om inget av detta fungerar kanske beroendet som drar in paketet inte längre är värt att behålla.

Vissa verktyg för software composition analysis lägger till reachability-analys, som kontrollerar om din kod över huvud taget kan anropa den sårbara funktionen, för att avgöra vilken av dessa åtgärder som kommer först. Se SCA-verktyg i jämförelse för alternativen.

Varför lockfilen inte är hela sanningen

De flesta verktyg bygger sin bild av transitiva beroenden utifrån lockfilen. Det fungerar när lockfilen finns, är aktuell och är det enda bygget installerar från. I CI är det ofta inte fallet:

  • Ingen lockfile. En requirements.txt med versionsintervall eller ett projekt som aldrig checkat in sin lockfile löses på nytt i varje bygge, så de transitiva versionerna kan ändras mellan byggen.
  • Cachar. CI-cachar återställer paket från tidigare körningar i stället för att hämta dem, och det de innehåller är inte alltid det som den aktuella lockfilen säger. Se vad GitHub Actions-cachen döljer.
  • Byggverktyg. Linters, kompilatorer, kodgeneratorer och setup-steg för in egna beroendeträd i bygget. De finns inte i applikationens manifest, men de körs med åtkomst till din källkod och dina hemligheter.
  • Installationsskript och nedladdningar. Ett pakets installationsskript kan hämta mer kod, och ett byggsteg kan ladda ner en binär direkt. Inget av dem lämnar en post i en lockfile.

Den enda kompletta registreringen av vilka transitiva beroenden som ingick i en release är en som görs medan releasen byggdes. SBOM:er från bygget förklarar skillnaden mellan att registrera ett bygge och att skanna dess filer i efterhand.

Transitiva beroenden och CRA

EU:s Cyber Resilience Act kräver att tillverkare tar fram en SBOM som omfattar "at the very least the top-level dependencies of the products" (bilaga I, del II, punkt 1). Transitiva beroenden nämns inte, så den rättsliga miniminivån är lägre än många guider antyder. Men CRA kräver också att du identifierar och hanterar sårbarheter i de komponenter som din produkt innehåller, och ett sårbart transitivt paket är en av dem. En SBOM som stannar vid den första nivån lämnar större delen av ditt beroendeträd utanför den processen. Se CRA:s krav på SBOM:er för detaljerna.

Så spårar CRACI transitiva beroenden

CRACI är en GitHub Actions-runner som registrerar bygget i stället för att skanna det. Medan varje jobb körs registrerar en paketmedveten proxy varje paket som jobbet hämtar, i alla led av trädet, inklusive paket som återställs från CI-cachar. Det ger en mer komplett bild av de beroenden som används än skannerbaserade verktyg.

  • Alla led, redovisat ärligt. Varje jobbs SBOM har en fullständighetsstatus, så du vet när en registrering inte kunde se allt.
  • Trädet synligt. En beroendegraf visar SBOM:ens beroendelager, i flera vyer.
  • Exporter som tar med dem. Exporter i CycloneDX och SPDX inkluderar transitiva beroenden, vart och ett med sin deklarerade licens.
  • Vilka byggen som berördes. När en ny sårbarhet dyker upp visar bygghistoriken vilka tidigare byggen som innehöll det sårbara paketet, direkt eller transitivt, så att du vet under vilken period du levererade det (se är vi drabbade av en CVE?). Historiken följer din lagringstid, 180 dagar som standard.
  • Policyspärrar. Ett bygge som innehåller en specifik CVE kan blockeras innan det levereras.

CRACI gör inte reachability-analys. Om du behöver veta om din kod anropar en sårbar funktion, kombinera det med ett SCA-verktyg som gör det. Se SBOM-generering i CRACI eller boka en demo för att registrera ett av dina egna byggen.

Transitiva beroenden: vanliga frågor

Vad är ett transitivt beroende?

Ett transitivt beroende är ett paket som din programvara använder eftersom ett annat paket behöver det. Om din app är beroende av bibliotek A och A är beroende av bibliotek B, så är B ett transitivt, eller indirekt, beroende för din app. Du har aldrig deklarerat det, men det levereras med din programvara.

Vad är skillnaden mellan ett direkt och ett transitivt beroende?

Ett direkt beroende är ett som du deklarerar i ditt manifest, till exempel package.json, pyproject.toml eller go.mod. Ett transitivt beroende är ett som dina direkta beroenden deklarerar, på vilket djup som helst. Du väljer direkta beroenden; pakethanteraren väljer transitiva när den löser trädet.

Är ett transient beroende samma sak som ett transitivt beroende?

Ja, i praktiken. ”Transient beroende” är en vanlig felsägning för ”transitivt beroende”. Den korrekta termen är transitivt, från den transitiva relationen: om A är beroende av B och B är beroende av C, så är A beroende av C.

Hur åtgärdar jag en sårbarhet i ett transitivt beroende?

Uppgradera först det direkta beroende som drar in det, om det finns en release med en åtgärdad version. Om inte, tvinga fram den åtgärdade versionen med din pakethanterares mekanism för åsidosättning, till exempel npm overrides, Yarn resolutions eller en constraints-fil för pip, och testa att föräldrapaketet fortfarande fungerar med den.

Hur listar jag alla transitiva beroenden?

Alla pakethanterare kan skriva ut det upplösta trädet: npm ls --all, pnpm list --depth Infinity, uv tree eller pipdeptree, go mod graph, cargo tree, mvn dependency:tree eller gradle dependencies. För vad ett produktionsbygge faktiskt installerade, registrera själva bygget.

Kräver EU:s Cyber Resilience Act transitiva beroenden i SBOM:en?

Förordningen sätter miniminivån vid "at the very least the top-level dependencies of the products" (bilaga I, del II, punkt 1). Transitiva beroenden nämns inte, men ett sårbart transitivt paket finns ändå i din produkt, och CRA kräver att du hanterar sårbarheter i de komponenter du levererar.

Se varje beroende som ditt bygge drog in

Kör ett GitHub Actions-arbetsflöde på CRACI och få en registrerad SBOM över varje paket det hämtade, i alla led av trädet.

Boka en demo