V roce 2026 o 131% více nahlášených CVE denně než loni.

Závislosti

Co je tranzitivní závislost?

Tranzitivní závislost je balíček, který váš software používá, protože ho potřebuje jiný balíček. Nikdy jste ho nedeklarovali, ale je v tom, co dodáváte, s vlastními zranitelnostmi a licencí. Zde je návod, jak je zobrazit, opravit a doložit, které z nich šly do každého vydání.

Aktualizováno

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

Přímé a tranzitivní závislosti

Přímou závislost deklarujete ve svém manifestu. Tranzitivní závislost deklarují vaše závislosti, jejich závislosti zase své, a tak dál, jak hluboko strom sahá. Správce balíčků při instalaci vyřeší celý strom a výsledek obvykle zapíše do lockfilu.

Vezměme aplikaci, která deklaruje jediný balíček, express. Příkaz npm ls --all ukáže, co tento jeden řádek přináší:

my-app
└─┬ express            ← přímá: deklarovali jste ji
  ├─┬ body-parser      ← tranzitivní, hloubka 1
  │ └── raw-body       ← tranzitivní, hloubka 2
  ├── cookie           ← tranzitivní, hloubka 1
  └─┬ send             ← tranzitivní, hloubka 1
    └── mime-types     ← tranzitivní, hloubka 2

Skutečný strom je delší. Většina balíčků v typické aplikaci přichází právě takto, což znamená, že většinu kódu, který dodáváte, vybral správce balíčků, ne vy.

Přímá závislost Tranzitivní závislost
Kdo ji vybral Váš tým, v manifestu Správce balíčků, podle manifestů vašich závislostí
Kde je uvedená Manifest a lockfile Lockfile, pokud existuje
Kdo řídí verzi Vy Rozsah verzí nadřazeného balíčku, pokud ho nepřepíšete
Jak opravíte zranitelnost Upgradem Upgradem nadřazeného balíčku nebo přepsáním verze

Proč na tranzitivních závislostech záleží

Nesou stejná rizika jako přímé závislosti, jen s menší viditelností a menší kontrolou.

  • Zranitelnosti. Když byla zveřejněna Log4Shell, zero-day zranitelnost v log4j, tým Open Source Insights společnosti Google našel 35 863 artefaktů v Maven Central, které závisely na dotčeném kódu log4j. Zhruba 7 000 z nich na něm záviselo přímo. Většina ho stahovala jako tranzitivní závislost a mnohé nešlo opravit, dokud opravu nevydal některý balíček mezi nimi.
  • Útoky na dodavatelský řetězec. Zadní vrátka v xz utils (CVE-2024-3094) se dostala do OpenSSH, aniž by OpenSSH na xz záviselo. Několik linuxových distribucí upravuje OpenSSH kvůli podpoře notifikací systemd a libsystemd závisí na liblzma, knihovně, kterou poskytuje xz.
  • Licence. Každý tranzitivní balíček má vlastní licenci. Copyleftová licence o tři úrovně níž je stejně závazná jako ta, kterou jste přidali sami.
  • Nekompatibilní změny. Nadřazený balíček, který přijímá rozsah verzí, pustí nové tranzitivní vydání dovnitř při příští čisté instalaci, i když se ve vašem manifestu nic nezměnilo.

Jak vypsat tranzitivní závislosti

Každý hlavní správce balíčků umí vypsat vyřešený strom:

Ekosystém Příkaz
npmnpm ls --all
pnpmpnpm list --depth Infinity
Python (uv)uv tree
Python (pip)pipdeptree
Gogo mod graph
Rustcargo tree
Mavenmvn dependency:tree
Gradlegradle dependencies

Chcete-li zjistit, proč tam konkrétní balíček je, zeptejte se na cestu k němu: npm explain <package>, pnpm why, yarn why nebo cargo tree -i <crate>. Pokud chcete s cestami pracovat, a ne je jen vypisovat, podívejte se na grafy závislostí.

Jak opravit zranitelnou tranzitivní závislost

  1. Upgradujte nadřazený balíček. Najděte přímou závislost, která balíček stahuje, a přejděte na vydání, které vyžaduje opravenou verzi. Je to nejčistší oprava, protože ji otestovali správci nadřazeného balíčku.
  2. Obnovte lockfile. Pokud rozsah verzí nadřazeného balíčku už opravenou verzi povoluje, stačí aktualizovat záznam v lockfilu, například pomocí cargo update -p <crate> nebo nového npm update.
  3. Přepište verzi. Pokud nadřazený balíček opravu nevydal, vynuťte verzi sami: overrides v npm a pnpm, resolutions v Yarn, soubor constraints u pip nebo vyšší požadavek v go.mod. Otestujte to, protože nadřazený balíček s touto verzí nikdy vydán nebyl.
  4. Nahraďte nebo odstraňte nadřazený balíček. Pokud nefunguje ani jedno, závislost, která balíček přináší, už možná nestojí za to si ponechat.

Některé nástroje pro analýzu softwarového složení přidávají analýzu dosažitelnosti, která ověřuje, zda váš kód může zranitelnou funkci vůbec zavolat, a podle ní určují, která z těchto oprav má přednost. Možnosti najdete ve srovnání nástrojů SCA.

Proč lockfile neřekne všechno

Většina nástrojů sestavuje svůj pohled na tranzitivní závislosti z lockfilu. Funguje to, když lockfile existuje, je aktuální a build instaluje jen z něj. V CI to často neplatí:

  • Žádný lockfile. Soubor requirements.txt s rozsahy verzí nebo projekt, který lockfile nikdy necommitoval, se při každém buildu řeší znovu, takže se tranzitivní verze mohou mezi buildy měnit.
  • Cache. Cache CI obnovují balíčky z dřívějších běhů místo jejich stažení a jejich obsah ne vždy odpovídá aktuálnímu lockfilu. Podívejte se, co cache GitHub Actions skrývá.
  • Nástroje pro build. Lintery, kompilátory, generátory kódu a kroky setup přinášejí do buildu vlastní stromy závislostí. Nejsou v manifestu vaší aplikace, ale běží s přístupem k vašemu zdrojovému kódu a tajným klíčům.
  • Instalační skripty a stahování. Instalační skript balíčku může stáhnout další kód a krok buildu může stáhnout binárku přímo. Ani jedno nezanechá záznam v lockfilu.

Jediný úplný záznam toho, které tranzitivní závislosti šly do vydání, je ten pořízený během buildu daného vydání. Stránka SBOM z doby buildu vysvětluje rozdíl mezi zaznamenáním buildu a dodatečným skenováním jeho souborů.

Tranzitivní závislosti a CRA

Cyber Resilience Act EU požaduje, aby výrobci vypracovali SBOM, která zahrnuje „přinejmenším nejdůležitější závislosti produktu“ (příloha I, část II, bod 1). Tranzitivní závislosti v něm uvedeny nejsou, takže zákonné minimum je nižší, než mnoho příruček naznačuje. CRA ale také požaduje, abyste identifikovali a řešili zranitelnosti v komponentách, které váš produkt obsahuje, a zranitelný tranzitivní balíček je jednou z nich. SBOM, která končí na první úrovni, vynechává z tohoto procesu většinu vašeho stromu závislostí. Podrobnosti najdete na stránce požadavky CRA na SBOM.

Jak CRACI sleduje tranzitivní závislosti

CRACI je runner GitHub Actions, který build zaznamenává, místo aby ho skenoval. Během každého jobu zaznamenává proxy, která rozumí balíčkům, každý balíček, který job stáhne, v jakékoli hloubce stromu, včetně balíčků obnovených z cache CI. To dává úplnější pohled na používané závislosti než nástroje založené na skenerech.

  • Každá hloubka, poctivě uvedená. SBOM každého jobu nese stav úplnosti, takže víte, kdy záznam nemohl vidět všechno.
  • Strom na očích. Graf závislostí zobrazuje vrstvy závislostí SBOM v několika pohledech.
  • Exporty, které je obsahují. Exporty CycloneDX a SPDX obsahují tranzitivní závislosti, každou s její deklarovanou licencí.
  • Které buildy byly dotčené. Když se objeví nová zranitelnost, historie buildů ukáže, které dřívější buildy obsahovaly zranitelný balíček, ať přímo, nebo tranzitivně, takže víte, v jakém období jste ho dodávali (viz týká se nás tato CVE?). Historie odpovídá vaší době uchování, ve výchozím nastavení 180 dní.
  • Policy gates. Build, který obsahuje konkrétní CVE, lze zablokovat dříve, než se dodá.

CRACI neprovádí analýzu dosažitelnosti. Pokud potřebujete vědět, zda váš kód volá zranitelnou funkci, zkombinujte ho s nástrojem SCA, který to umí. Podívejte se na generování SBOM v CRACI, nebo si rezervujte demo a zaznamenejte některý ze svých buildů.

Tranzitivní závislosti: časté dotazy

Co je tranzitivní závislost?

Tranzitivní závislost je balíček, který váš software používá, protože ho potřebuje jiný balíček. Pokud vaše aplikace závisí na knihovně A a A závisí na knihovně B, pak je B tranzitivní, neboli nepřímou, závislostí vaší aplikace. Nikdy jste ji nedeklarovali, ale dodává se s vaším softwarem.

Jaký je rozdíl mezi přímou a tranzitivní závislostí?

Přímou závislost deklarujete ve svém manifestu, například v package.json, pyproject.toml nebo go.mod. Tranzitivní závislost deklarují vaše přímé závislosti, v jakékoli hloubce. Přímé závislosti vybíráte vy; tranzitivní vybírá správce balíčků, když řeší strom.

Je „transient dependency“ totéž co tranzitivní závislost?

V praxi ano. „Transient dependency“ je v angličtině častá záměna za „transitive dependency“. Správný termín je tranzitivní, podle tranzitivní relace: pokud A závisí na B a B závisí na C, pak A závisí na C.

Jak opravím zranitelnost v tranzitivní závislosti?

Nejprve upgradujte přímou závislost, která ji stahuje, pokud existuje vydání s opravenou verzí. Pokud ne, vynuťte opravenou verzi mechanismem přepsání ve vašem správci balíčků, například npm overrides, Yarn resolutions nebo souborem constraints u pip, a otestujte, že s ní nadřazený balíček stále funguje.

Jak vypíšu všechny tranzitivní závislosti?

Každý správce balíčků umí vypsat vyřešený strom: npm ls --all, pnpm list --depth Infinity, uv tree nebo pipdeptree, go mod graph, cargo tree, mvn dependency:tree nebo gradle dependencies. Abyste věděli, co produkční build skutečně nainstaloval, zaznamenejte samotný build.

Vyžaduje Cyber Resilience Act EU tranzitivní závislosti v SBOM?

Nařízení stanoví minimum jako „přinejmenším nejdůležitější závislosti produktu“ (příloha I, část II, bod 1). Tranzitivní závislosti v něm uvedeny nejsou, ale zranitelný tranzitivní balíček je stále ve vašem produktu a CRA požaduje, abyste řešili zranitelnosti v komponentách, které dodáváte.

Podívejte se na každou závislost, kterou váš build stáhl

Spusťte jedno workflow GitHub Actions na CRACI a získejte zaznamenanou SBOM každého balíčku, který stáhlo, v jakékoli hloubce stromu.

Rezervujte si demo