We wtorek po południu pojawia się opis krytycznej podatności w bibliotece, o której większość zespołu słyszy pierwszy raz. Producent jednego z systemów już wydał komunikat, dystrybucja Linuksa przygotowuje pakiety, a na kanałach branżowych krąży gotowy kod ataku.

Pierwsze pytanie, które pada w firmie, nie brzmi „jak to załatać”. Brzmi: czy my w ogóle tego używamy, gdzie i w jakiej wersji.

SBOM (Software Bill of Materials) to czytelny maszynowo wykaz komponentów jednego konkretnego wydania oprogramowania — z wersjami, dostawcami, sumami kontrolnymi i zależnościami między nimi. Powstał po to, żeby odpowiedź na powyższe pytanie zajmowała minuty, a nie dni.

Problem w tym, że w większości firm takiego wykazu po prostu nie ma. Jest lista serwerów. Jest lista aplikacji. Jest monitoring i backup. Nie ma natomiast niczego, co opisywałoby, z czego składa się każda z tych aplikacji: jakie biblioteki weszły do niej podczas budowania, co pociągnęły za sobą jako własne zależności, jaka wersja siedzi w obrazie kontenera sprzed pół roku i który z trzech systemów kupionych od zewnętrznych dostawców zawiera podatny komponent w środku.

Odpowiedź powstaje wtedy ręcznie. Ktoś loguje się na kolejne hosty, uruchamia menedżera pakietów, przegląda katalogi aplikacji, pisze do dwóch dostawców i czeka. W dobrym przypadku zajmuje to dzień. W typowym — kilka dni, a wynik i tak jest niepełny, bo nikt nie zajrzał do zależności zależności.

Wykaz składników nie skraca samej naprawy. Skraca ustalanie faktów — i o to w nim chodzi.

Najważniejsze wnioski

  • SBOM odpowiada na pytanie o skład, a nie o ryzyko. Wykaz mówi, jakie komponenty i w jakich wersjach wchodzą w skład konkretnego artefaktu oraz jak są ze sobą powiązane. Ocena, czy któryś z nich jest podatny i czy da się to wykorzystać, powstaje dopiero po zestawieniu wykazu z danymi o podatnościach i po sprawdzeniu, co w danym środowisku faktycznie działa.
  • Wartość SBOM ujawnia się w tempie odpowiedzi. Bez wykazu ustalenie, gdzie w firmie znajduje się dana biblioteka, jest pracą ręczną rozłożoną na dni i obarczoną błędem pominięcia. Z wykazem jest to zapytanie do rejestru, a czas przechodzi z ustalania faktów na podejmowanie decyzji.
  • Zależności tranzytywne są tym, czego nie widać w pliku projektu. Aplikacja deklaruje kilkanaście bibliotek, a w wyniku budowania trafia do niej kilkaset. Podatność zwykle dotyczy tej drugiej warstwy — komponentu, którego nikt świadomie nie wybierał.
  • Obecność komponentu to jeszcze nie możliwość ataku. Podatny kod bywa nieosiągalny, wyłączony konfiguracją albo niewywoływany przez aplikację. Ten wniosek wymaga jednak dowodu technicznego i zapisu — służy do tego dokument VEX, a nie notatka w zgłoszeniu.
  • Wykaz bez cyklu życia starzeje się w tempie zmian w kodzie. SBOM opisuje jedno konkretne wydanie. Każda zmiana zależności, przebudowa obrazu i aktualizacja pakietów systemowych unieważniają poprzedni dokument, więc wykaz powstaje razem z artefaktem, a nie raz na kwartał.
  • Obowiązki prawne dotyczą producentów, nie każdego użytkownika. Wymóg sporządzenia SBOM z rozporządzenia (UE) 2024/2847 (CRA) obciąży od 11 grudnia 2027 r. producenta produktu z elementami cyfrowymi. Firma, która oprogramowanie wyłącznie używa, nie jest jego adresatem — ale ma interes w tym, żeby wykazu zażądać od dostawcy.

Czym jest SBOM

Software Bill of Materials to ustrukturyzowany, przeznaczony do odczytu maszynowego wykaz komponentów wchodzących w skład oprogramowania wraz z relacjami między nimi. Rozporządzenie CRA definiuje go w art. 3 pkt 39 jako formalny zapis zawierający szczegółowe informacje o składnikach wchodzących w skład elementów oprogramowania produktu z elementami cyfrowymi oraz o relacjach w łańcuchu dostaw tych składników.

Analogia z listą materiałów w produkcji jest trafna tylko do pewnego momentu. Wykaz materiałów w fabryce opisuje rzeczy fizyczne, które można policzyć. Wykaz składników oprogramowania opisuje coś, co bywa rekurencyjne: biblioteka pociąga bibliotekę, ta pociąga kolejną, a przy dziesiątej warstwie nikt już nie pamięta, skąd się wzięła.

Minimalne elementy: z siedmiu pól NTIA do siedemnastu CISA

Zestaw pól, które wykaz powinien nieść, nie jest kwestią gustu. Punktem odniesienia był przez lata dokument NTIA „The Minimum Elements For a Software Bill of Materials (SBOM)” z 12 lipca 2021 r. z siedmioma polami: dostawca, nazwa komponentu, wersja, inne unikatowe identyfikatory, relacja zależności, autor danych SBOM i znacznik czasu.

29 lipca 2026 r. CISA wraz z NSA, FBI i partnerami międzynarodowymi — wśród współautorów jest polski NASK — opublikowała dokument „2026 Minimum Elements for a Software Bill of Materials (SBOM)”, który zastąpił opracowanie NTIA. Zmiana jest istotna, bo pól jest teraz siedemnaście i dzielą się one na dwie grupy: metadane samego dokumentu SBOM i dane o komponentach.

Tabelę można przewijać w poziomie.

Minimalne elementy SBOM: NTIA 2021 i wydanie CISA z 2026 roku. Zestawienie pokazuje kierunek zmiany — z siedmiu pól opisujących głównie komponent do siedemnastu, w tym metadanych o samym dokumencie i narzędziu, które go wytworzyło.
Obszar NTIA 2021 CISA 2026
Liczba pól danych 7 17
Identyfikacja komponentu Supplier Name, Component Name, Version, Other Unique Identifiers Component Producer, Component Name, Component Version, Component Identifiers
Integralność Hash tylko jako pole zalecane Component Hash Algorithm i Component Hash Value jako elementy minimalne
Pochodzenie dokumentu Author of SBOM Data, Timestamp SBOM Author, SBOM Author Signature, SBOM Tool Name i Version, SBOM Generation Context, SBOM Version, znacznik czasu wg RFC 9557
Głębokość wykazu Depth — dopuszczalne wskazanie „known unknowns” Coverage — wszystkie komponenty łącznie z zależnościami przechodnimi, bez ustalonej minimalnej głębokości
Uznane formaty SPDX, CycloneDX, znaczniki SWID SPDX i CycloneDX; znaczniki SWID usunięte

Trzy rzeczy w tej zmianie mają praktyczne znaczenie. Po pierwsze, suma kontrolna komponentu przestała być polem opcjonalnym — bez niej wykaz opisuje deklarowaną tożsamość pliku, a nie jego rzeczywistą zawartość. Po drugie, dokument ma nieść informację o tym, czym i w jakim momencie został wygenerowany, bo wykaz ze skanu gotowego obrazu i wykaz z procesu budowania to dwa różne dokumenty o różnej wiarygodności. Po trzecie, wymóg pokrycia obejmuje wprost zależności przechodnie.

Zależności bezpośrednie i tranzytywne

To rozróżnienie jest sednem całego zagadnienia.

Zależność bezpośrednia to komponent, który świadomie wybrał programista i który jest wymieniony w pliku projektu — w package.json, requirements.txt, pom.xml, composer.json, go.mod.

Zależność tranzytywna (przechodnia) to komponent, który wszedł do aplikacji dlatego, że potrzebowała go któraś z zależności bezpośrednich. Nikt go nie wybierał, nikt nie czytał jego opisu, a często nikt nie wie o jego istnieniu, dopóki nie pojawi się w wynikach skanowania.

Proporcje między tymi dwiema grupami są zwykle nieintuicyjne. Aplikacja deklarująca dwadzieścia bibliotek potrafi po zbudowaniu zawierać kilkaset komponentów. Praktyczny wniosek jest prosty: jeżeli inwentaryzacja kończy się na pliku projektu, obejmuje kilka procent tego, co faktycznie uruchamia się na produkcji.

Dlaczego lista pakietów to jeszcze nie wykaz składników

Odruchowa reakcja administratora brzmi: przecież mam dpkg -l, mam pip freeze, mam package.json. To prawda, ale każde z tych źródeł odpowiada na inne, węższe pytanie.

package.json i requirements.txt opisują deklarację, czyli to, o co poprosił programista. Nie opisują wyniku rozwiązania zależności. Ten sam plik zbudowany dziś i pół roku temu daje dwa różne zestawy komponentów, jeżeli zakresy wersji były luźne. Plik blokady (package-lock.json, poetry.lock, go.sum) jest już bliżej prawdy, bo utrwala konkretne wersje — ale nadal opisuje jeden ekosystem, nie zawiera dostawcy, licencji ani sum kontrolnych i nie mówi nic o tym, co znalazło się w obrazie kontenera poza katalogiem aplikacji.

dpkg -l i rpm -qa opisują pakiety systemowe zainstalowane menedżerem pakietów. Nie widzą binariów rozpakowanych z archiwum do /opt, bibliotek dowiązanych statycznie, plików JAR skopiowanych ręcznie ani zależności aplikacji zainstalowanych narzędziem języka programowania.

Różnice sprowadzają się do czterech rzeczy, których lista pakietów nie ma:

  1. Jednego dokumentu dla całego artefaktu. SBOM łączy warstwę systemu operacyjnego, warstwę środowiska uruchomieniowego i warstwę aplikacji w jeden opis jednego, konkretnego wydania.
  2. Relacji między komponentami. Lista pakietów jest płaska. Wykaz niesie graf: co od czego zależy i przez którą zależność wszedł podatny komponent.
  3. Ustandaryzowanych identyfikatorów. Nazwa pakietu w jednej dystrybucji, w drugiej i w rejestrze bibliotek to trzy różne napisy opisujące ten sam kod. Bez wspólnego identyfikatora automatyczne dopasowanie do bazy podatności jest zgadywaniem.
  4. Formatu do odczytu maszynowego. Wynik polecenia w terminalu nadaje się do przeczytania przez człowieka na jednym hoście. Wykaz w ustalonym formacie nadaje się do zapytania obejmującego kilkaset artefaktów naraz.

SBOM, CMDB i skaner podatności — trzy różne warstwy

Te trzy rzeczy bywają mylone, bo wszystkie „coś inwentaryzują”. Odpowiadają jednak na rozłączne pytania i żadna nie zastępuje pozostałych.

Tabelę można przewijać w poziomie.

Trzy warstwy wiedzy o środowisku i pytania, na które odpowiadają. Najwięcej mówi kolumna „Czego nie zawiera”: opisuje, czego w danym źródle po prostu nie ma.
Warstwa Na jakie pytanie odpowiada Jednostka opisu Czego nie zawiera
CMDB Jakie zasoby mamy, kto nimi zarządza i co od czego zależy na poziomie usług Host, usługa, konto, certyfikat, umowa Składu oprogramowania: nie wie, jakie biblioteki są wewnątrz aplikacji
SBOM Z czego składa się konkretne wydanie oprogramowania Komponent i relacja zależności Kontekstu zasobu i oceny podatności: nie wie, gdzie ten artefakt działa ani czy jest podatny
Skaner podatności Które ze znanych podatności pasują do tego, co widzi na hoście Wykrycie (para: zasób i podatność) Kompletnego składu: widzi to, co potrafi rozpoznać, i tylko w momencie skanu

Wynika z tego układ, który warto mieć na uwadze przy planowaniu pracy. Ewidencja zasobów w postaci CMDB mówi, gdzie coś stoi i kto za to odpowiada. SBOM mówi, co jest w środku. Proces zarządzania podatnościami korzysta z obu i dokłada priorytet oraz termin. Brak którejkolwiek warstwy widać w konkretnym momencie: bez CMDB nie wiadomo, komu przypisać naprawę; bez SBOM nie wiadomo, czego szukać; bez procesu podatności zostaje lista faktów bez decyzji.

Dwa formaty: CycloneDX i SPDX

W praktyce liczą się dwa formaty. Oba przeszły ścieżkę normalizacyjną, ale w różnych organizacjach i na różnym etapie.

CycloneDX powstał w OWASP i jest rozwijany wspólnie przez OWASP Foundation oraz komitet TC54 Ecma International. Bieżącą wersją specyfikacji jest 1.7 z 21 października 2025 r., a odpowiadającą jej normą — ECMA-424 w drugim wydaniu z grudnia 2025 r. Dokument serializuje się do JSON, XML albo Protocol Buffers.

SPDX powstał w Linux Foundation. Wersja 2.2.1 jest normą ISO/IEC 5962:2021. Bieżącą wersją specyfikacji jest 3.0.1 z 17 grudnia 2024 r.; wersja 3.x jest przedmiotem prac normalizacyjnych ISO jako ISO/IEC DIS 5962 i na dzień publikacji tego materiału nie jest jeszcze opublikowaną normą. SPDX 3.0 przeszedł na model danych oparty na RDF z serializacją JSON-LD i porzucił dawne formaty tag:value oraz arkusza kalkulacyjnego.

Historyczne rozróżnienie — CycloneDX „do bezpieczeństwa”, SPDX „do licencji” — jest dziś w dużej mierze nieaktualne: CycloneDX niesie dane licencyjne z wyrażeniami SPDX, a SPDX 3.0 ma pełny profil Security z klasami VEX oraz ocenami CVSS, EPSS i SSVC. O wyborze decyduje więc to, co obsługują narzędzia po obu stronach wymiany.

Tabelę można przewijać w poziomie.

CycloneDX 1.7 i SPDX 3.0.1 — różnice, które widać w pracy. Zestawienie dotyczy stanu na 30 sierpnia 2026 r.; oba formaty są uznane w wydaniu minimalnych elementów SBOM z 2026 roku.
Cecha CycloneDX SPDX
Bieżąca wersja 1.7 (21 października 2025) 3.0.1 (17 grudnia 2024)
Status normalizacyjny ECMA-424, wydanie 2. (grudzień 2025) ISO/IEC 5962:2021 dla SPDX 2.2.1; wersja 3.x jako ISO/IEC DIS 5962 w toku
Serializacja JSON, XML, Protocol Buffers Serializacje RDF: JSON-LD, Turtle, N-Triples, RDF/XML
Identyfikator komponentu Pola purl i cpe w obiekcie komponentu packageUrl oraz externalIdentifier z typami cpe23, packageUrl, cve
Graf zależności Tablica dependencies z polami ref i dependsOn Relacje contains i dependsOn między elementami
Deklaracja kompletności compositions.aggregate z wartościami complete, incomplete i wariantami Brak bezpośredniego odpowiednika; kompletność opisuje się relacjami i adnotacjami
Dane o podatnościach i VEX Tablica vulnerabilities z obiektem analysis w tym samym schemacie Profil Security z klasami relacji VEX

Jak wygląda pojedynczy komponent

Poniżej skrócony fragment dokumentu CycloneDX w formacie JSON. Nie jest to kompletny wykaz, tylko jeden wpis komponentu wraz z odpowiadającą mu krawędzią grafu zależności.

{
  "bomFormat": "CycloneDX",
  "specVersion": "1.7",
  "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79",
  "version": 1,
  "metadata": {
    "timestamp": "2026-08-30T09:14:02Z",
    "component": {
      "type": "application",
      "bom-ref": "pkg:maven/com.firma/aplikacja@5.2.0",
      "name": "aplikacja",
      "version": "5.2.0"
    }
  },
  "components": [
    {
      "type": "library",
      "bom-ref": "pkg:maven/org.example/parser@2.14.1",
      "name": "parser",
      "group": "org.example",
      "version": "2.14.1",
      "purl": "pkg:maven/org.example/parser@2.14.1",
      "hashes": [
        { "alg": "SHA-256", "content": "8f14e45fceea167a5a36dedd4bea2543..." }
      ],
      "licenses": [{ "expression": "Apache-2.0" }]
    }
  ],
  "dependencies": [
    {
      "ref": "pkg:maven/com.firma/aplikacja@5.2.0",
      "dependsOn": ["pkg:maven/org.example/parser@2.14.1"]
    }
  ]
}

Warto zwrócić uwagę na trzy rzeczy. purl jest identyfikatorem, po którym da się automatycznie odpytać bazę podatności. hashes niesie skrót zawartości komponentu: pozwala wykryć, że dwa pliki o tej samej nazwie i wersji mają inną treść, i rozpoznać konkretny artefakt po samej zawartości. Sam skrót nie rozstrzyga natomiast, który z nich pochodzi od producenta — do tego trzeba porównać go z wartością otrzymaną zaufanym kanałem albo zweryfikować podpis lub poświadczenie opisujące pochodzenie artefaktu. Tablica dependencies niesie informację, przez którą zależność komponent wszedł do artefaktu — a to jest dokładnie ta informacja, której brakuje przy podatności w bibliotece tranzytywnej.

Odpowiednik w SPDX 3.0.1 jest zapisany w JSON-LD i posługuje się innym nazewnictwem: identyfikatorem elementu jest spdxId, wersją packageVersion, dostawcą suppliedBy, a adres pakietu niesie dedykowana właściwość packageUrl. Zależności wyraża się relacjami dependsOn i contains między elementami, a nie osobną tablicą.

Identyfikatory: purl i CPE

Wykaz bez jednoznacznego identyfikatora komponentu jest listą napisów. Dopiero identyfikator pozwala automatycznie zestawić go z bazą podatności.

Package URL (purl) opisuje pakiet w kategoriach ekosystemu, z którego pochodzi. Składnia ma siedem części — scheme:type/namespace/name@version?qualifiers#subpath — z których wymagane są scheme, type i name. Od grudnia 2025 r. purl jest normą Ecma International o numerze ECMA-427. Przykłady dla różnych ekosystemów:

pkg:npm/%40company/nazwa-pakietu@1.4.2
pkg:pypi/django@5.1.4
pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1
pkg:deb/debian/openssl@3.0.15-1~deb12u1?arch=amd64
pkg:oci/aplikacja@sha256:1f2e3d4c5b6a?repository_url=rejestr.firma.pl%2Faplikacja

CPE (Common Platform Enumeration) w wersji 2.3 jest zdefiniowane w NIST IR 7695 i ma zupełnie inną konstrukcję: jedenaście pól rozdzielonych dwukropkami, gdzie gwiazdka oznacza „dowolna wartość”, a myślnik „nie dotyczy”. Ta konstrukcja pozwala na dopasowania grupujące: gwiazdka w polu wersji obejmuje wszystkie wersje produktu naraz, czego purl nie potrafi. Rzeczywistych zakresów „od–do” sam identyfikator jednak nie niesie — opisują je dopiero pola versionStartIncluding i versionEndExcluding w regule dopasowania po stronie NVD.

cpe:2.3:a:apache:log4j:2.14.1:*:*:*:*:*:*:*

Oba identyfikatory mają problemy, o których warto wiedzieć przed pierwszym rozczarowaniem wynikami dopasowania.

CPE bywa nadawane dopiero po opublikowaniu podatności, więc początkowe zgłoszenie zwykle go nie zawiera. Nazewnictwo producenta i produktu w słowniku CPE bywa niejednoznaczne, a błąd normalizacji nazwy przekłada się wprost na błąd korelacji. Do tego doszła zmiana o dużym znaczeniu praktycznym: 15 kwietnia 2026 r. NIST porzucił zasadę wzbogacania każdego rekordu CVE i przeszedł na priorytetyzację. Pierwszeństwo dostały wpisy z katalogu KEV, oprogramowanie używane w administracji federalnej USA i „critical software” według Executive Order 14028; pozostałe rekordy trafiają do kategorii najniższego priorytetu, bez zaplanowanego terminu analizy. Ponieważ wzbogacanie obejmuje właśnie przypisanie list produktów, czyli CPE, dla znacznej części nowych rekordów CPE po prostu nie powstaje.

purl ma inne ograniczenia. Specyfikacja nie definiuje uniwersalnej metody porównywania wersji między typami pakietów. Nazwy w PyPI podlegają normalizacji, więc naiwne porównanie napisów potrafi rozminąć się z rekordem. Typ golang ma udokumentowaną wadę projektową: bez dostępu do kodu albo do serwera pośredniczącego modułów nie da się rozstrzygnąć, co jest modułem, a co pakietem.

Praktyczna konsekwencja jest jedna: w wykazie warto umieszczać oba identyfikatory, jeżeli oba są znane. Dokładnie to zaleca wydanie minimalnych elementów SBOM z 2026 roku, które wymaga co najmniej jednego identyfikatora komponentu i rekomenduje podanie wszystkich dostępnych. Uzasadnienie jest rozbrajająco szczere: uniwersalne rozwiązanie problemu identyfikacji oprogramowania jeszcze nie istnieje.

Trzecim źródłem, o którym warto pamiętać przy dopasowaniu, jest OSV. Format ten identyfikuje pakiet parą „ekosystem plus nazwa” i wyraża wersje podatne przez zakresy ze zdarzeniami introduced, fixed, last_affected — a więc w kategoriach, w których faktycznie myśli menedżer pakietów, a nie w kategoriach słownika produktów.

Jak wygenerować SBOM: dwie drogi i dwie różne wiarygodności

Są dwie drogi i różnią się nie tylko narzędziem, ale też tym, co da się na podstawie wyniku powiedzieć.

W procesie budowania

Wykaz wytworzony podczas budowania artefaktu ma dostęp do rozwiązanego grafu zależności: wie, którą wersję menedżer pakietów faktycznie wybrał i przez którą zależność bezpośrednią weszła. To zwykle najlepszy dostępny wgląd w relacje między komponentami: pokazuje, przez którą zależność bezpośrednią wszedł komponent tranzytywny, i obejmuje także to, co nie zostawia śladu w gotowym artefakcie. Kompletność zależy jednak od ekosystemu i od generatora — wynik jest silnie związany ze środowiskiem, w którym build się wykonał, część zależności pośrednich i rozstrzyganych dopiero w czasie działania bywa trudna do uchwycenia, a wersje bibliotek ładowanych dynamicznie mogą nie odpowiadać tym, które system faktycznie załaduje. Dlatego wykaz z procesu budowania i wykaz ze skanu nie wykluczają się, tylko uzupełniają: skan zbudowanego obrazu również wyliczy komponenty tranzytywne — nie powie natomiast, kto je pociągnął, a od tego zależy plan naprawy. Warunek jest jeden — musi powstawać automatycznie, obok binariów, a nie jako osobne zadanie uruchamiane przez człowieka.

Ze skanu gotowego systemu albo obrazu

Druga droga dotyczy wszystkiego, czego nie budujemy sami: obrazów kontenerów pobranych z rejestru, serwerów utrzymywanych od lat, aplikacji dostarczonych przez producenta. Narzędzie przegląda system plików i bazy menedżerów pakietów, rozpoznaje komponenty i składa z nich wykaz.

Jednym z najczęściej używanych narzędzi otwartoźródłowych jest Syft. Polecenie generujące wykaz nazywa się dziś syft scan; dawne syft packages nadal działa, ale jest oznaczone jako przestarzałe.

Poniżej kolejno: wykaz dla obrazu kontenera w formacie CycloneDX, wykaz dla katalogu z rozpakowanym artefaktem w formacie SPDX i wykaz dla całego działającego systemu.

syft scan registry:rejestr.firma.pl/aplikacja:5.2.0 -o cyclonedx-json=sbom-aplikacja-5.2.0.cdx.json
syft scan dir:/opt/aplikacja -o spdx-json=sbom-opt-aplikacja.spdx.json
sudo syft scan dir:/ --exclude ./proc --exclude ./sys --exclude ./dev -o cyclonedx-json=sbom-host.cdx.json

Trzy uwagi do ostatniego wiersza. Skan całego systemu uruchamia się z uprawnieniami roota — bez nich narzędzie pominie katalogi, do których nie ma dostępu, i zwróci wykaz krótszy, niż wynika ze stanu hosta. Wykluczenia dotyczą systemów plików generowanych przez jądro; bez nich przejście po / trwa wielokrotnie dłużej. Wzorzec registry: sięga do rejestru bezpośrednio, więc dla rejestru prywatnego wymaga wcześniejszego zalogowania.

Alternatywą jest Trivy, który generuje wykaz przełącznikiem --format w podpoleceniach image, fs i vm:

trivy image --format spdx-json --output sbom-obrazu.spdx.json alpine:3.22
trivy fs --format cyclonedx --output sbom-projektu.cdx.json /opt/projekt

Jedna rzecz w zachowaniu Trivy’ego bywa myląca: przy --format cyclonedx skanowanie podatności jest domyślnie wyłączone. Aby otrzymać wykaz razem z podatnościami, trzeba jawnie dodać --scanners vuln. Dokumentacja narzędzia wprost o tym uprzedza.

Wykazy w formacie CycloneDX generuje też cdxgen — narzędzie z tego samego projektu co sam format. W środowiskach Microsoftu odpowiednikiem jest sbom-tool, który produkuje wyłącznie dokumenty SPDX: domyślnie w wersji 2.2, a w 3.0 po dodaniu -mi SPDX:3.0.

Czego skan nie zobaczy

Ograniczenie tej metody jest wpisane w jej konstrukcję. Narzędzie rozpoznaje to, co potrafi rozpoznać: bazę dpkg, metadane pakietów języka programowania, znane układy katalogów. Syft dla Debiana i Ubuntu czyta wprost plik /var/lib/dpkg/status (a w obrazach typu distroless katalog /var/lib/dpkg/status.d/), a nie wynik dpkg-query. Skan katalogu, w którym tego pliku nie ma, zwróci więc wykaz bez pakietów systemowych — i nie będzie to informacja o ich braku.

Poza zasięgiem zostaje kod dowiązany statycznie, biblioteka wkompilowana w binarium, plik JAR przepakowany razem z zależnościami do jednego archiwum ze zmianą nazw pakietów oraz każdy komponent skopiowany do systemu bez metadanych. Wykaz ze skanu jest więc z definicji niekompletny — i dobrze, jeżeli mówi o tym wprost polem compositions.aggregate w CycloneDX, z wartościami complete i incomplete.

Gdzie przechowywać wykazy SBOM i jak nimi zarządzać

Plik SBOM leżący w katalogu domowym administratora nie różni się funkcjonalnie od jego braku. Wykaz ma sens wtedy, gdy da się go odpytać — i to nie o jeden artefakt, tylko o wszystkie naraz.

Kilka zasad, które sprawdzają się niezależnie od wybranego narzędzia:

  • Wykaz jest przypisany do konkretnego wydania, nie do aplikacji. Nazwa pliku, nazwa projektu w rejestrze albo etykieta artefaktu musi zawierać wersję. „SBOM aplikacji sklep” to dokument bez wartości dowodowej; „SBOM aplikacji sklep 5.2.0, wygenerowany 30 sierpnia 2026 podczas budowania” już nią jest.
  • Każda zmiana zależności unieważnia poprzedni wykaz. Dotyczy to również przebudowy obrazu na nowej wersji obrazu bazowego, gdzie kod aplikacji się nie zmienił, a warstwa systemowa owszem.
  • Wykazy przechowuje się razem z artefaktem albo obok niego. Rejestr obrazów obsługujący artefakty referencyjne, repozytorium binariów, wydania w systemie kontroli wersji — dowolne miejsce, w którym artefakt i jego wykaz nie rozjadą się w czasie.
  • Sufiks nazwy pliku niesie format. To nie jest estetyka: część narzędzi — między innymi osv-scanner — wybiera parser wyłącznie na podstawie nazwy i plik sbom.json po prostu pominie. Konwencja to *.cdx.json dla CycloneDX i *.spdx.json dla SPDX.
  • Potrzebny jest jeden punkt zapytania. Służą do tego platformy analizy komponentów; przykładem rozwiązania otwartoźródłowego jest OWASP Dependency-Track — flagowy projekt OWASP, który przyjmuje dokumenty CycloneDX przez API i utrzymuje strukturę „projekt plus wersja”, dzięki czemu pytanie „które nasze wydania zawierają tę bibliotekę” jest jednym zapytaniem, a nie przeglądem hostów. Trzeba jednak wiedzieć, na co się piszemy: to osobna usługa, a nie pakiet — serwer API z własną bazą danych, kopia zapasowa, aktualizacje, certyfikat i klucze API. Jeżeli na to nie ma miejsca, tymczasowym punktem zapytania jest katalog wykazów w repozytorium kodu i wyszukiwanie po identyfikatorach purl. To rozwiązanie gorsze, ale nadal jedno miejsce zamiast czterdziestu.
  • Wykaz z podpisem jest weryfikowalny, wykaz bez podpisu jest deklaracją. Wydanie minimalnych elementów z 2026 roku umieściło podpis autora wykazu wśród elementów obowiązkowych właśnie dlatego, że dokument przechodzi między organizacjami. Dla artefaktów w rejestrze OCI robi to cosign attest --predicate sbom-aplikacja-5.2.0.cdx.json --type cyclonedx rejestr.firma.pl/aplikacja:5.2.0, a odbiorca sprawdza podpis poleceniem cosign verify-attestation. Wykaz zostaje wtedy dowiązany do obrazu jako artefakt referencyjny — czyli nie rozjedzie się z artefaktem i daje się zweryfikować.

Pierwszy tydzień na istniejącej flocie

Większość firm nie zaczyna od procesu budowania, bo niczego sama nie buduje. Punkt startu wygląda wtedy tak.

Krok pierwszy to narzędzie. Syft i Grype nie są pakietami dystrybucji — pobiera się binarium wydania z repozytorium projektu, sprawdza sumę kontrolną i podpis, a dopiero potem rozkłada na hosty. To dokładnie ten wymóg, który stawiamy dostawcom, więc wypada zastosować go do siebie.

Krok drugi to wykazy dla floty i jeden punkt zapytania. Przy kilkudziesięciu hostach wystarczy jedna pętla po liście adresów: dla każdego hosta powstaje osobny plik, a zaraz po jego wygenerowaniu ten sam plik trafia do rejestru komponentów. Znacznik wersji ustalamy raz, przed pętlą, żeby wszystkie wykazy z jednego przebiegu opisywała ta sama wersja; projektem jest host lub aplikacja, wersją zaś data albo numer wydania. Docelowo jest to zadanie w harmonogramie, a nie polecenie uruchamiane ręcznie.

wersja="$(date +%F)"

while IFS= read -r host; do
  wykaz="sbom-$host-$wersja.cdx.json"

  ssh -n "$host" 'sudo syft scan dir:/ --exclude ./proc --exclude ./sys --exclude ./dev -o cyclonedx-json' \
    > "$wykaz" || { echo "pominięto $host: skan nie powiódł się" >&2; continue; }

  printf 'X-Api-Key: %s\n' "$DT_API_KEY" |
    curl -sS --fail-with-body -H @- -X POST https://dtrack.firma.pl/api/v1/bom \
      -F autoCreate=true \
      -F projectName="$host" \
      -F projectVersion="$wersja" \
      -F bom=@"$wykaz"
done < hosty.txt

Trzy szczegóły decydują o tym, czy pętla przejdzie przez całą listę. ssh -n odłącza zdalne polecenie od standardowego wejścia — bez tego pierwsze połączenie wciągnęłoby resztę pliku hosty.txt i przebieg skończyłby się po jednym hoście. --fail-with-body sprawia, że cURL kończy się kodem błędu przy odpowiedzi 4xx albo 5xx i nadal wypisuje jej treść; bez tego odrzucone wgranie wygląda tak samo jak przyjęte. -H @- każe cURL-owi wczytać nagłówek ze standardowego wejścia, więc sam klucz nie staje się argumentem widocznym na liście procesów. Zmienna środowiskowa daje tylko tyle, że sekret nie jest wpisany na stałe w skrypcie — powłoka podstawia jej wartość przed uruchomieniem polecenia, więc przy zapisie -H "X-Api-Key: $DT_API_KEY" klucz i tak trafiał do argumentów procesu.

Po tych dwóch krokach pytanie „gdzie mamy tę bibliotekę” przestaje wymagać logowania na hosty. To jeszcze nie jest pełne wdrożenie — brakuje wykazów z procesu budowania dla własnych aplikacji i stanowisk dostawców dla systemów zamkniętych — ale jest to stan, w którym wykaz zaczyna odpowiadać na pytania.

Od wykazu do decyzji

Tu zaczyna się część, w której najłatwiej o rozczarowanie. Zestawienie wykazu z bazą podatności nie daje listy problemów do naprawienia. Daje listę kandydatów, którą trzeba dopiero sprawdzić.

Dopasowanie i jego pułapki

Mechanizm jest prosty: dla każdego komponentu z wykazu narzędzie sprawdza, czy jego identyfikator i wersja mieszczą się w zakresie opisanym w rekordzie podatności. Praktyka jest mniej prosta.

Fałszywe trafienia biorą się głównie z ziarnistości identyfikatorów. Jeżeli dwa różne warianty oprogramowania mają w słowniku jeden identyfikator, dopasowanie obejmie oba. Do tego dochodzą poprawki przenoszone selektywnie do starszych gałęzi: dystrybucja może wydać pakiet z numerem wersji sprzed poprawki, w którym poprawka już jest — narzędzie dopasowujące po samym numerze zgłosi podatność, której tam nie ma.

Fałszywe pominięcia biorą się z braków w danych. Jeżeli rekord podatności nie ma identyfikatora CPE, dopasowanie po CPE go nie znajdzie. Po zmianie polityki NVD z kwietnia 2026 roku dotyczy to sporej części nowych rekordów, co przekłada się bezpośrednio na skuteczność narzędzi opartych wyłącznie na tym identyfikatorze. Praktyczny wniosek: lepiej korzystać z narzędzia, które sięga do kilku źródeł naraz — OSV z zakresami wersji dla ekosystemów pakietów, europejskiej bazy EUVD prowadzonej przez ENISA, danych dystrybucji i biuletynów producenta — niż do jednego.

Trzeci mechanizm dotyczy pakietów systemowych i daje wynik cichy oraz optymistyczny. Dopasowanie do poprawek dystrybucji wymaga informacji, o jaką dystrybucję i wydanie chodzi; narzędzie odczytuje ją z /etc/os-release w chwili generowania wykazu i zapisuje w metadanych dokumentu. Wykaz zbudowany dla samego katalogu aplikacji, wykaz otrzymany od dostawcy i wykaz po konwersji formatu często tej informacji nie mają — wtedy skaner nie zgłasza dla pakietów systemowych niczego. Krótki raport nie znaczy w tej sytuacji „czysto”, tylko „nie było czego porównać”. Sprawdza się to raz, na wykazie, o którym wiadomo, że zawiera podatny pakiet.

Dwa pierwsze polecenia czytają gotowy wykaz i ich wynik nie zależy od dostępu do samego artefaktu; Trivy rozpoznaje format wejściowy automatycznie. Trzecie pokazuje inną drogę — przechodzi rekurencyjnie po katalogu i czyta pliki blokady oraz wykazy rozpoznane po nazwie pliku:

grype sbom:./sbom-aplikacja-5.2.0.cdx.json
trivy sbom ./sbom-aplikacja-5.2.0.cdx.json
osv-scanner scan source -r /opt/projekt

Analiza ekspozycji, czyli krok, którego nie da się pominąć

Dopasowanie mówi: „w tym artefakcie jest komponent w wersji objętej opisem podatności”. Nie mówi, czy podatność da się w tym konkretnym wdrożeniu wykorzystać. Między jednym a drugim jest kilka pytań, na które odpowiada wyłącznie ktoś, kto zna aplikację:

  • Czy podatny kod w ogóle znajduje się w artefakcie? Bywa, że biblioteka jest obecna, ale bez modułu, którego dotyczy problem.
  • Czy podatna funkcja jest wywoływana? Obecność klasy w archiwum nie oznacza, że aplikacja jej używa.
  • Czy dane napastnika mogą do niej dotrzeć? Podatność w parserze przetwarzającym wyłącznie pliki konfiguracyjne z dysku ma inny profil ryzyka niż ta sama podatność w parserze obsługującym ruch z Internetu.
  • Czy istniejąca konfiguracja ją blokuje? Wyłączony moduł, ustawienie zmieniające domyślne zachowanie, ograniczenie po stronie serwera aplikacyjnego.

Odpowiedź „u nas to nie jest wykorzystywalne” bywa w tym miejscu poprawna. Problemem staje się dopiero wtedy, gdy nie zostaje nigdzie zapisana.

Zero-day: gdy nie ma jeszcze rekordu ani poprawki

Sytuacja, w której wykaz daje najwięcej, wygląda inaczej niż rutynowe skanowanie. Pojawia się informacja o aktywnie wykorzystywanej podatności w konkretnej bibliotece — czasem zanim powstanie rekord CVE, prawie zawsze zanim skanery zaktualizują swoje bazy, a nierzadko zanim producent wyda poprawkę.

W tym momencie skaner podatności milczy, bo nie ma czego dopasować. Wykaz milczeć nie musi: pytanie „czy w którymkolwiek z naszych wydań jest ta biblioteka i w jakiej wersji” nie wymaga żadnego rekordu ani bazy. Wystarczy identyfikator pakietu i zapytanie do rejestru komponentów.

To zmienia kolejność pracy. Zamiast czekać na aktualizację bazy skanera, zespół dostaje listę artefaktów do przejrzenia w kilka minut i może od razu przejść do dwóch rzeczy, które przy zero-dayu liczą się najbardziej: ustalenia, czy podatna funkcja jest u nas osiągalna, oraz zastosowania obejścia opisanego w komunikacie, dopóki nie ma poprawki. Kiedy poprawka się pojawi, ta sama lista mówi, co przebudować.

Warunek jest ten sam co zawsze i warto go powtórzyć: to działa tylko wtedy, gdy wykazy istnieją zawczasu. Wykaz generowany w dniu zdarzenia opisuje stan, który trzeba dopiero ustalić — czyli dokładnie tę pracę, której miał oszczędzić.

VEX: zapis tego, czy podatność faktycznie dotyczy produktu

Vulnerability Exploitability eXchange to format, w którym producent albo zespół utrzymujący aplikację zapisuje wynik takiej analizy w postaci nadającej się do odczytu maszynowego. CISA opublikowała minimalne wymagania dla VEX w kwietniu 2023 roku.

Konstrukcja jest prosta: dokument zawiera oświadczenia, a każde oświadczenie wiąże dokładnie jeden status z dokładnie jedną podatnością dla jednego lub wielu produktów. Statusy są cztery:

  • not_affected — działania naprawcze nie są wymagane,
  • affected — autor zaleca podjęcie działań,
  • fixed — wskazane wersje zawierają poprawkę,
  • under_investigation — analiza trwa, status się zmieni.

Przy statusie not_affected liczy się uzasadnienie i tu CISA wymienia pięć dopuszczalnych wartości: component_not_present, vulnerable_code_not_present, vulnerable_code_not_in_execute_path, vulnerable_code_cannot_be_controlled_by_adversary oraz inline_mitigations_already_exist. To nie jest lista dowolnych wymówek — każda z tych wartości opisuje inny mechanizm i inny rodzaj dowodu, którego wymaga.

Nośników jest kilka i różnią się słownikiem. Profil VEX w CSAF 2.0 (standard OASIS) używa nazw fixed, known_affected, known_not_affected, under_investigation. OpenVEX przejmuje nazewnictwo CISA bez zmian, ale jest wciąż wersją roboczą — v0.2.0 z sierpnia 2023 roku pozostaje ostatnim wydaniem. CycloneDX nie ma osobnego schematu VEX i wyraża go polem analysis w obiekcie podatności, z własnym, szerszym słownikiem stanów (resolved, resolved_with_pedigree, exploitable, in_triage, false_positive, not_affected) i dziewięcioma własnymi uzasadnieniami.

Trzy rzeczy warto zapamiętać. VEX i SBOM są niezależne: dokument VEX nie wymaga wykazu, a wykaz nie wymaga VEX-a — CISA nazywa VEX koncepcją powiązaną z SBOM, nie jego elementem. Brak oświadczenia nie oznacza not_affected; w VEX nie ma statusu domyślnego. Statusu nie dziedziczy się w dół łańcucha dostaw — to, że twórca biblioteki uznał podatność za niewykorzystywalną u siebie, nie przenosi się automatycznie na produkt, który tę bibliotekę zawiera.

SBOM w czterech typowych sytuacjach

Poniższe przykłady są modelowe — opisują typowy układ, a nie zdarzenie u konkretnego klienta. Skala i szczegóły techniczne odpowiadają jednak temu, co spotyka się w środowiskach liczących kilkadziesiąt hostów.

Krytyczna podatność w bibliotece: gdzie ją mamy

Pojawia się opis krytycznej podatności w bibliotece używanej przez aplikacje w jednym z języków programowania. Pytanie brzmi: gdzie ją mamy.

Bez wykazów odpowiedź powstaje ręcznie: przejście po hostach, menedżer pakietów, katalogi aplikacji, obrazy w rejestrze. Dla warstwy systemowej idzie to sprawnie, dla aplikacyjnej znacznie gorzej, bo trzeba wejść w każdy artefakt osobno. Realny czas to od kilkunastu godzin do kilku dni, a największym problemem nie jest długość, tylko to, że nie da się powiedzieć, czy przegląd był kompletny.

Z wykazami przypisanymi do wydań i wgranymi do rejestru komponentów to jedno zapytanie o nazwę pakietu, które zwraca listę wydań wraz z wersjami komponentu. Odpowiedź powstaje w kilka minut i można ją powtórzyć następnego dnia, kiedy okaże się, że zakres wersji podatnych został skorygowany.

Trzeba tu jednak zachować proporcje. Amerykańska Cyber Safety Review Board — rada powołana w 2022 r. przy Departamencie Bezpieczeństwa Krajowego i rozwiązana w styczniu 2025 r. — analizując po fakcie sprawę podatności w bibliotece Log4j (CVE-2021-44228, ujawniona 10 grudnia 2021 r., ocena bazowa CVSS 10,0), odnotowała, że żadna z organizacji używających SBOM, z którymi Rada rozmawiała, nie wykorzystała ich do zidentyfikowania podatnych wdrożeń. Powodem były między innymi braki informacji o wersjach komponentów. Wykaz pomaga, jeżeli jest kompletny, aktualny i zawiera wersje. Sam fakt jego posiadania nie pomaga.

Podatny komponent jest zależnością zależności

To sytuacja typowa, nie wyjątkowa. Zespół sprawdza plik projektu, nie znajduje podatnej biblioteki i zamyka temat. Biblioteka jest jednak w artefakcie — weszła jako zależność jednej z zadeklarowanych bibliotek.

Skalę tego zjawiska dobrze pokazuje analiza ekosystemu Javy wykonana przez zespół Open Source Insights firmy Google w grudniu 2021 roku, przy okazji podatności w Log4j. Po doprecyzowaniu, że podatny jest wyłącznie artefakt log4j-core, liczba dotkniętych pakietów w repozytorium Maven Central przekraczała 17 tysięcy, czyli około 4% ekosystemu. Istotniejsza jest jednak druga liczba: dla ponad 80% dotkniętych pakietów podatność leżała głębiej niż jeden poziom zależności, u większości z nich sięgała pięciu poziomów w głąb grafu zależności, a w skrajnych przypadkach dziewięciu.

Wykaz z grafem zależności odpowiada nie tylko na pytanie „czy mamy”, ale też „przez co”. Ta druga odpowiedź jest tą, która pozwala zaplanować naprawę: aktualizacja podatnej biblioteki wprost często nie jest możliwa, bo o jej wersji decyduje komponent wyżej.

Komponent jest, ale podatny kod nie jest osiągalny

Skaner zgłasza podatność w bibliotece obsługującej format danych. Analiza pokazuje, że aplikacja używa tej biblioteki wyłącznie do odczytu własnych plików konfiguracyjnych przy starcie, a podatna funkcja parsowania nigdy nie jest wywoływana z danymi pochodzącymi z zewnątrz.

Wniosek „to nas nie dotyczy” jest tu prawdopodobnie poprawny. Nie wolno go jednak zapisać jako statusu bez dowodu technicznego, i to z trzech powodów.

Po pierwsze, „nie widzę, żeby to było wywoływane” to nie to samo co „to nie jest wywoływane”. Dowodem jest analiza ścieżek wywołań albo test, a nie przegląd kodu prowadzony pod presją czasu.

Po drugie, wniosek jest ważny dla jednej wersji aplikacji. Następne wydanie może zacząć używać tej samej biblioteki inaczej, a status przeniesiony bezrefleksyjnie stanie się fałszywy.

Po trzecie, przy tej samej bibliotece może pojawić się druga podatność — w module, który akurat jest używany. Status dotyczy pary „produkt i podatność”, nie samej biblioteki.

Dlatego ten wniosek zapisuje się jako oświadczenie VEX ze statusem not_affected i uzasadnieniem vulnerable_code_not_in_execute_path, z datą, autorem i wskazaniem wersji produktu, której dotyczy. Wtedy przy kolejnym skanie nikt nie zaczyna od zera, a przy audycie jest co pokazać.

Producent dostarcza urządzenie albo system i nie mówi, co jest w środku

Najczęstszy przypadek w małych i średnich firmach: system kupiony od zewnętrznego dostawcy, zamknięty, aktualizowany wyłącznie przez producenta. Skaner podatności widzi otwarte porty i wersję usługi, ale nic nie wie o bibliotekach w środku.

Zdarzenie z marca 2024 roku pokazuje, dlaczego to nie jest problem czysto formalny. W pakiecie xz — kompresji obecnej w praktycznie każdej dystrybucji Linuksa — wykryto celowo wprowadzony kod (CVE-2024-3094, sklasyfikowany jako CWE-506, czyli osadzony złośliwy kod). Dotyczyło to wersji 5.6.0 i 5.6.1. Istotny jest sposób. Zaciemniony ładunek leżał w repozytorium jako pliki testowe i sam z siebie był nieszkodliwy; kod, który podczas budowania wypakowywał go i wstrzykiwał do biblioteki liblzma, dokładano wyłącznie do archiwów wydaniowych. Ani przegląd repozytorium, ani numer wersji niczego więc nie zdradzały, a wykaz składników pokazałby xz w wersji 5.6.0 i nic ponadto — z punktu widzenia nazwy i numeru wszystko się zgadzało.

Wniosek jest podwójny. Wykaz komponentów pomaga odpowiedzieć na pytanie „czy mamy tę wersję” i to jest realna pomoc, bo dystrybucje wskazały konkretne wersje do wycofania. Nie zabezpiecza natomiast przed sytuacją, w której złośliwa zmiana wchodzi do artefaktu o poprawnej nazwie i numerze — na to odpowiadają sumy kontrolne, podpisy artefaktów i kontrola procesu budowania, a nie sam wykaz.

Dostawcy warto zadać pięć pytań:

  1. Czy dostarczacie wykaz składników dla wydawanych wersji, w formacie CycloneDX albo SPDX?
  2. Czy wykaz obejmuje zależności przechodnie, czy tylko komponenty najwyższego poziomu?
  3. W jakim terminie po ujawnieniu krytycznej podatności otrzymamy stanowisko, czy dotyczy ona waszego produktu — i w jakiej formie?
  4. Czy publikujecie oświadczenia VEX albo doradztwa bezpieczeństwa w formacie do odczytu maszynowego?
  5. Jak długo dana wersja produktu będzie otrzymywać poprawki bezpieczeństwa?

Odpowiedź „nie udostępniamy takich informacji” też jest odpowiedzią i warto ją odnotować w ocenie ryzyka dostawcy. Sama ocena dostawcy jest zresztą wymagana — piszę o tym w części o NIS2 i ustawie o KSC.

Czego SBOM nie zapewnia

Ta lista jest równie ważna jak lista zastosowań, bo najkosztowniejszym błędem przy wdrażaniu SBOM jest przekonanie, że sam wykaz coś zabezpiecza.

  • Nie ocenia ryzyka. Mówi, co jest w środku. Ocena wymaga danych o podatnościach, wiedzy o ekspozycji zasobu i decyzji o priorytecie.
  • Nie gwarantuje kompletności. Wykaz z procesu budowania odwzorowuje rozwiązany graf zależności; wykaz ze skanu obejmuje tylko to, co narzędzie rozpoznało. Różnicę deklaruje się polem compositions.aggregate, ale sama deklaracja nie zmienia zakresu — zmienia go moment, w którym wykaz powstaje.
  • Nie chroni przed złośliwą zmianą w komponencie o poprawnej nazwie i wersji. Odpowiadają na to sumy kontrolne, podpisy i kontrola procesu budowania.
  • Nie jest dowodem zgodności z regulacją. Jest jednym z artefaktów, których regulacja może wymagać.
  • Nie odpowiada na pytanie o wykorzystywalność. Do tego służy analiza ekspozycji, a jej wynik zapisuje VEX.

SBOM a wymagania prawne

Ta część bywa źródłem nieporozumień, bo obowiązki są węższe, niż wynikałoby z branżowych podsumowań. Poniższe opisuje stan prawny na 30 sierpnia 2026 r. i nie jest poradą prawną — w konkretnym przypadku kwalifikacja podmiotu wymaga analizy z prawnikiem.

CRA: obowiązek producenta, nie użytkownika

Rozporządzenie Parlamentu Europejskiego i Rady (UE) 2024/2847 — Cyber Resilience Act — zostało opublikowane w Dzienniku Urzędowym 20 listopada 2024 r. i weszło w życie 10 grudnia 2024 r. Wymóg dotyczący wykazu składników jest w załączniku I część II pkt 1, do którego odsyła art. 13 ust. 8: producent ma identyfikować i dokumentować podatności oraz komponenty, w tym przez sporządzenie SBOM w powszechnie używanym formacie nadającym się do odczytu maszynowego, obejmującego co najmniej zależności najwyższego poziomu produktów. Sam wymóg zacznie być stosowany 11 grudnia 2027 r. — o kalendarzu niżej.

Cztery rzeczy w tym przepisie warto przeczytać dokładnie.

Po pierwsze, adresatem jest producent produktu z elementami cyfrowymi, a nie każda firma używająca oprogramowania. Rozporządzenie wiąże obowiązki z czynnością — wytwarzaniem albo udostępnianiem produktu na rynku — a nie z korzystaniem z niego; w art. 3 słowo „użytkownik” nie pojawia się w ogóle jako podmiot obowiązany. Warto przy tym wiedzieć, że definicja podmiotu gospodarczego z art. 3 pkt 12 nie jest listą zamkniętą: po wyliczeniu producenta, upoważnionego przedstawiciela, importera i dystrybutora następuje klauzula obejmująca każdą inną osobę podlegającą obowiązkom związanym z wytwarzaniem albo udostępnianiem produktu na rynku. Granicę wyznacza więc czynność, a nie nazwa roli.

Po drugie, firma może w tę rolę wejść, ale tylko w dwóch układach. Art. 21 uznaje za producenta importera albo dystrybutora, który wprowadza produkt do obrotu pod własną nazwą lub znakiem towarowym albo dokonuje istotnej modyfikacji produktu już wprowadzonego do obrotu. Art. 22 obejmuje inne osoby — spoza kręgu producenta, importera i dystrybutora — które dokonują istotnej modyfikacji i udostępniają produkt na rynku. „Istotna modyfikacja” jest przy tym terminem zdefiniowanym w art. 3 pkt 30: to zmiana po wprowadzeniu do obrotu, która wpływa na zgodność z wymaganiami z załącznika I część I albo zmienia przeznaczenie produktu. Modyfikacja na własny, wewnętrzny użytek, bez udostępnienia produktu na rynku, roli producenta nie tworzy. Art. 22 ust. 2 zawęża dodatkowo zakres — obowiązki z art. 13 i 14 obejmują tę część produktu, której dotyczy modyfikacja, a cały produkt dopiero wtedy, gdy modyfikacja wpływa na jego cyberbezpieczeństwo jako całości. Osobną kategorią adresatów są opiekunowie oprogramowania otwartego z art. 24, którzy producentami nie są, a mimo to mają własne, węższe obowiązki.

Po trzecie, wymagany zakres to co najmniej zależności najwyższego poziomu. To znacznie mniej, niż sugeruje potoczne rozumienie SBOM — a jednocześnie znacznie mniej, niż potrzeba do odpowiedzi na pytania z poprzednich sekcji, bo warstwa tranzytywna jest właśnie tą, w której zwykle siedzi problem.

Po czwarte, CRA nie wymaga publikowania wykazu ani przekazywania go klientom. Motyw 77 stwierdza wprost, że producenci nie powinni być zobowiązani do upubliczniania SBOM. Wykaz jest elementem dokumentacji technicznej (załącznik VII), a organ nadzoru rynku sięga po dokumentację na uzasadnione żądanie (art. 13 ust. 22). Jeżeli producent zdecyduje się udostępnić wykaz użytkownikom, ma wskazać, gdzie można go uzyskać (załącznik II pkt 9) — ale sama decyzja należy do niego.

Rozporządzenie nie wskazuje też konkretnego formatu: nazwy CycloneDX ani SPDX w jego tekście nie padają. Doprecyzowanie formatu i elementów pozostawiono aktom wykonawczym Komisji (art. 13 ust. 24), a jest to uprawnienie fakultatywne. Na dzień publikacji tego materiału taki akt nie został wydany.

Kalendarz stosowania

Daty z art. 71 są trzy i łatwo je pomylić:

Tabelę można przewijać w poziomie.

Kalendarz stosowania rozporządzenia (UE) 2024/2847 według art. 71. Stan na 30 sierpnia 2026 r. — rozporządzenie obowiązuje w całości od 10 grudnia 2024 r., ale stosuje się dotąd wyłącznie rozdział IV; obowiązek zgłaszania z art. 14 zaczyna być stosowany 11 września 2026 r., a wymagania załącznika I — 11 grudnia 2027 r.
Data Czego dotyczy Stan na 30 sierpnia 2026
10 grudnia 2024 Wejście w życie rozporządzenia Nastąpiło
11 czerwca 2026 Rozdział IV (art. 35–51): notyfikacja jednostek oceniających zgodność Stosowany
11 września 2026 Art. 14: zgłaszanie aktywnie wykorzystywanych podatności i poważnych incydentów Jeszcze nie stosowany
11 grudnia 2027 Pełne stosowanie, w tym wymagań z załącznika I — a więc i obowiązku SBOM Jeszcze nie stosowany

Obowiązek zgłoszeniowy z art. 14 jest trójstopniowy i biegnie dwiema ścieżkami o różnych terminach końcowych. Dla aktywnie wykorzystywanej podatności: wczesne ostrzeżenie w ciągu 24 godzin, zgłoszenie podatności w ciągu 72 godzin i sprawozdanie końcowe nie później niż 14 dni po udostępnieniu środka naprawczego albo ograniczającego ryzyko. Dla poważnego incydentu wpływającego na bezpieczeństwo produktu: te same 24 i 72 godziny, ale sprawozdanie końcowe w terminie miesiąca od zgłoszenia incydentu. Zgłoszenie idzie jednocześnie do CSIRT wyznaczonego jako koordynator i do ENISA, przez wspólną platformę zgłoszeniową z art. 16.

Kalendarz z art. 71 uzupełnia przepis przejściowy z art. 69. Produkty wprowadzone do obrotu przed 11 grudnia 2027 r. podlegają wymaganiom rozporządzenia — w tym obowiązkowi wykazu składników — tylko wtedy, gdy od tej daty zostaną poddane istotnej modyfikacji (art. 69 ust. 2). Wyjątkiem są obowiązki zgłoszeniowe z art. 14: obejmują one wszystkie produkty w zakresie rozporządzenia, również wprowadzone do obrotu wcześniej (art. 69 ust. 3).

NIS2 i ustawa o krajowym systemie cyberbezpieczeństwa

Powiedzmy wprost: ani dyrektywa NIS2, ani polska ustawa o KSC nie wymagają SBOM. W tekście dyrektywy (UE) 2022/2555 skrót ten nie występuje ani razu.

Art. 21 ust. 2 lit. d NIS2 mówi o bezpieczeństwie łańcucha dostaw, „w tym aspektach związanych z bezpieczeństwem dotyczących stosunków między każdym podmiotem a jego bezpośrednimi dostawcami lub usługodawcami”. Polskim odpowiednikiem jest art. 8 ust. 1 pkt 2 lit. e ustawy o KSC w brzmieniu nadanym nowelizacją z 23 stycznia 2026 r. (Dz.U. 2026 poz. 252), która weszła w życie 3 kwietnia 2026 r. Ten przepis również nie wymienia inwentaryzacji komponentów oprogramowania.

Bliżej tematu jest art. 21 ust. 3 NIS2: przy doborze środków z ust. 2 lit. d podmiot ma uwzględnić podatności charakterystyczne dla każdego bezpośredniego dostawcy i usługodawcy oraz ogólną jakość ich produktów i praktyk cyberbezpieczeństwa, w tym procedury bezpiecznego opracowywania. Polski art. 8 ust. 2 ustawy o KSC każe uwzględnić cztery rzeczy: podatności związane z dostawcą sprzętu lub oprogramowania, ogólną jakość produktów, usług i procesów ICT pochodzących od tego dostawcy, wyniki skoordynowanej oceny bezpieczeństwa przeprowadzonej przez Grupę Współpracy oraz wyniki postępowania z art. 67b. Zwrot o procedurach bezpiecznego opracowywania nie został do ustawy przeniesiony. Wykaz składników nie pojawia się w żadnym z tych przepisów — jest jednym z możliwych sposobów wykazania jakości praktyk dostawcy, nie jedynym i nie wymaganym.

Dziesięć kategorii podmiotów — od dostawców usług DNS i rejestrów nazw domen najwyższego poziomu, przez dostawców usług chmurowych i ośrodków przetwarzania danych, po internetowe platformy handlowe i wyszukiwarki — stosuje na podstawie art. 8b ust. 1 ustawy o KSC środki zarządzania ryzykiem określone w rozporządzeniu wykonawczym (UE) 2024/2690; samo rozporządzenie obejmuje dodatkowo dostawców usług zaufania. Załącznik do niego ma w pkt 6.1.2 lit. c wymóg, aby proces nabywania usług i produktów ICT obejmował „informacje opisujące elementy sprzętu i oprogramowania wykorzystywane w usługach ICT lub produktach ICT”. To najbliższy odpowiednik wymogu wykazu poza CRA — ale rozporządzenie nie używa słowa SBOM i nie schodzi do poziomu bibliotek. Wymóg wykazu aktywów z pkt 12.4 tego samego załącznika dotyczy zasobów, czyli poziomu, który w tym materiale nazywamy ewidencją, a nie składu oprogramowania. Szerzej opisuje to materiał o przygotowaniu infrastruktury pod NIS2 i KSC.

Stany Zjednoczone: kierunek się zmienił

Ten zwrot warto odnotować, bo w materiałach branżowych wciąż krąży nieaktualny obraz. Memorandum OMB M-26-05 z 23 stycznia 2026 r. uchyliło memoranda M-22-18 i M-23-16, a wraz z nimi ogólne oczekiwanie samoatestacji i SBOM przy zakupach federalnych. Żądanie wykazu jest dziś opcją umowną agencji, a nie obowiązkiem. Powiązana sprawa regulacyjna FAR 2023-002 została zamknięta. Nie znaczy to, że temat zniknął — wydanie minimalnych elementów SBOM z lipca 2026 roku powstało już po tej zmianie i jest wspólnym dokumentem CISA, NSA, FBI oraz partnerów międzynarodowych.

Cykl życia wykazu i powiązanie z procesami

Wykaz składników nie jest projektem z datą zakończenia. Jest strumieniem dokumentów powstających razem z artefaktami i konsumowanych przez kilka istniejących już procesów.

Powiązanie z aktualizacjami. Wykaz odpowiada na pytanie, których hostów i wydań dotyczy dana zmiana, zanim ktoś zaplanuje okno serwisowe. Bez tego kolejność zmian ustala się na podstawie pamięci zespołu — a to jest dokładnie ta sytuacja, w której powstają problemy opisane w materiale o aktualizacjach serwerów Linux w produkcji. Zależność działa też w drugą stronę: po aktualizacji powstaje nowy artefakt, a więc i nowy wykaz.

Powiązanie z ewidencją zasobów. Wykaz opisuje artefakt; ewidencja mówi, gdzie ten artefakt działa i kto za niego odpowiada. Połączenie obu warstw wymaga jednej rzeczy: żeby wpis w ewidencji zawierał identyfikator wydania, a nie tylko nazwę aplikacji.

Powiązanie z zarządzaniem podatnościami. Wykaz jest źródłem danych na wejściu, nie procesem. Priorytet, termin i status naprawy powstają w procesie opisanym w materiale o zarządzaniu podatnościami z użyciem CVSS, EPSS i KEV.

Powiązanie z powierzchnią ataku. Komponent w artefakcie działającym w izolowanym segmencie i ten sam komponent w usłudze wystawionej do Internetu to dwa różne priorytety. Perspektywę zewnętrzną porządkuje zarządzanie zewnętrzną powierzchnią ataku, a wykaz odpowiada na drugą połowę pytania: co dokładnie działa pod tym adresem.

Powiązanie z reagowaniem na incydenty. Podczas incydentu wykaz skraca ustalanie faktów w trzech miejscach: pozwala sprawdzić, czy podejrzany komponent w ogóle był w wydaniu działającym w chwili zdarzenia, wskazuje pozostałe wydania z tym samym komponentem, czyli zakres przeglądu, a po odbudowie pozwala potwierdzić, że nowy artefakt zawiera już wersję z poprawką. Najważniejsza jest ta pierwsza rola: wykaz zapisany razem z wydaniem opisuje stan sprzed incydentu, a skan przeprowadzony po nim opisuje stan już po zmianach, i tej różnicy nie da się odtworzyć później. To ta sama praca, którą opisuje materiał o pierwszych sześćdziesięciu minutach incydentu — tyle że wykonana wcześniej i zapisana. Wykaz powstanie jednak tylko dla artefaktu, o którym wiadomo, że istnieje; resztę domyka praca nad shadow IT.

Co realnie zatrzymuje wdrożenie

Ograniczenia dokumentu opisała sekcja wyżej. Wdrożenia kończą jednak częściej ograniczenia organizacji i środowiska, o których w opracowaniach zwykle nie ma słowa.

Hosty, na których nic nie wolno zainstalować. Systemy utrzymywane przez dostawcę albo objęte zamrożeniem zmian obsługuje się z zewnątrz: skanem obrazu maszyny wirtualnej albo kopii systemu plików, a nie narzędziem uruchamianym na produkcji.

Systemy zbyt stare dla narzędzia. Binarium skanera bywa zbudowane pod nowsze wersje bibliotek systemowych, niż ma dziesięcioletni serwer. Dla takich hostów zostaje wykaz z listy pakietów i jawna adnotacja o niekompletności — gorszy dokument jest lepszy niż jego brak, pod warunkiem że wiadomo, czego w nim nie ma.

Jeden administrator na kilkadziesiąt hostów. Skan floty jest zadaniem automatu w harmonogramie, a nie pozycją w kalendarzu człowieka. Jeżeli po miesiącu wykazy nie odświeżają się same, wdrożenie już się skończyło — tylko nikt tego jeszcze nie zauważył.

Wdrożenie zatrzymuje się na pilotażu. Skala zjawiska jest mierzalna: w badaniu ENISA z czerwca 2026 r. 78% organizacji zadeklarowało rozpoczęcie wdrożenia wykazów składników, ale 44% było wciąż na etapie pilotażu albo wdrożenia ograniczonego do części środowiska.

Pierwszy skan zwraca za dużo. Kilka tysięcy wykryć na czterdziestu hostach to normalny wynik pierwszego przebiegu i typowy moment porzucenia tematu. Ratunkiem jest zawężenie: najpierw artefakty osiągalne z Internetu, potem systemy przetwarzające dane krytyczne, dopiero na końcu reszta. Kolejność ustala proces opisany w materiale o zarządzaniu podatnościami, a nie liczba wykryć.

Zamykanie wykryć bez zapisu uzasadnienia. Wniosek „to nas nie dotyczy” zapisany w komentarzu do zgłoszenia jest jednorazowy — przy następnym skanie ktoś przechodzi tę samą analizę od zera, a za trzecim razem ją skraca. Ten sam wniosek zapisany jako oświadczenie VEX zostaje.

Najczęstsze pytania

Czy SBOM jest obowiązkowy?

Zależy od roli. Producent produktu z elementami cyfrowymi wprowadzanego na rynek unijny będzie miał taki obowiązek na podstawie załącznika I część II pkt 1 rozporządzenia (UE) 2024/2847, stosowanego w pełni od 11 grudnia 2027 r. Firma, która oprogramowanie wyłącznie używa, nie jest adresatem tego przepisu — chyba że dokona istotnej modyfikacji produktu i udostępni go na rynku, bo wtedy art. 22 uznaje ją za producenta. Ani NIS2, ani polska ustawa o krajowym systemie cyberbezpieczeństwa nie posługują się pojęciem SBOM i nie nakazują wprost inwentaryzacji bibliotek. Dla części podmiotów istnieje jednak wymóg zbliżony: art. 8b ust. 1 ustawy o KSC każe stosować rozporządzenie wykonawcze (UE) 2024/2690, a jego załącznik w pkt 6.1.2 lit. c wymaga informacji opisujących elementy sprzętu i oprogramowania wykorzystywane w nabywanych usługach i produktach ICT.

Czy SBOM zastępuje skaner podatności?

Nie. Wykaz mówi, co jest w środku; skaner porównuje to z bazą znanych podatności. Te dwie rzeczy działają razem — wykaz podnosi skuteczność skanowania, bo pozwala odpytać bazę o komponenty, których skaner nie rozpoznałby na hoście. Kierunek odwrotny też jest prawdziwy: skaner bez wykazu widzi tylko to, co potrafi rozpoznać na miejscu.

Czy SBOM zawiera informacje o podatnościach?

Sam wykaz — nie, i celowo. Podatności zmieniają się codziennie, skład artefaktu jest niezmienny. CycloneDX dopuszcza umieszczenie danych o podatnościach w tym samym dokumencie, ale przewodnik OWASP zaleca ich rozdzielenie i wskazanie komponentu odwołaniem, właśnie ze względu na różny okres ważności obu rodzajów danych.

Jak często aktualizować wykaz i czy potrzebny jest dla każdego wydania?

Wykaz powstaje przy każdym wydaniu artefaktu, a nie w stałym rytmie kalendarzowym. Wydanie 5.2.0 i 5.2.1 to dwa różne zestawy komponentów, nawet jeżeli różnica dotyczy jednej biblioteki — a szczególnie wtedy, bo właśnie ta różnica bywa przedmiotem pytania. Dla systemów, których nie budujemy sami, rytmem jest ponowny skan po każdej większej aktualizacji oraz okresowy, na przykład miesięczny, dla wykrycia zmian wprowadzonych poza procesem.

CycloneDX czy SPDX?

Oba są uznanymi formatami w wydaniu minimalnych elementów SBOM z 2026 roku, ale ich status normalizacyjny jest różny: CycloneDX 1.7 odpowiada normie ECMA-424 w wydaniu drugim, a po stronie SPDX opublikowaną normą ISO pozostaje ISO/IEC 5962:2021 dla wersji 2.2.1 — bieżąca linia 3.x jest dopiero projektem ISO/IEC DIS 5962. Praktycznie decyduje to, co obsługują narzędzia po obu stronach: CycloneDX jest natywnym formatem OWASP Dependency-Track i większości narzędzi zorientowanych na bezpieczeństwo aplikacji, SPDX bywa oczekiwany tam, gdzie liczy się zgodność licencyjna i dłuższa historia normalizacji ISO. Rozkład użycia potwierdza badanie ENISA z czerwca 2026 r. na próbie 334 organizacji: CycloneDX wskazuje 44% respondentów, SPDX 29%. Syft, Trivy i cdxgen potrafią wygenerować oba, a konwersja między nimi jest możliwa, choć bywa stratna.

Czy da się wygenerować wykaz dla istniejącego serwera?

Tak. syft scan dir:/ przejdzie po systemie plików i złoży wykaz z baz menedżerów pakietów oraz metadanych aplikacji. To punkt wyjścia dla systemów, których nie budujemy sami — z jednym zastrzeżeniem opisanym wyżej: taki wykaz jest z definicji niekompletny. Warto oznaczyć go jako niekompletny już przy wgraniu do rejestru, inaczej po pół roku nikt nie odróżni go od wykazu z procesu budowania.

Czy wykaz składników ujawnia poufne informacje?

Może ujawniać: lista komponentów mówi coś o architekturze produktu, a niekiedy wskazuje, których podatności szukać. CRA nie wymaga upubliczniania wykazów — motyw 77 stwierdza to wprost, choć nie podaje powodu — a wykaz udostępniany kontrahentom zwykle podlega umowie o poufności. To argument za kontrolą dostępu do wykazów, nie za rezygnacją z ich tworzenia.

Czy znalezienie podatnej biblioteki oznacza, że aplikację da się zaatakować?

Nie. Obecność komponentu w wersji objętej opisem podatności jest przesłanką, nie dowodem. Podatny kod może być nieosiągalny, niewywoływany albo zablokowany konfiguracją. Ten wniosek wymaga jednak sprawdzenia i zapisu jako oświadczenie VEX — z jednym z pięciu uzasadnień, a jeżeli żadne nie pasuje, z opisowym oświadczeniem o wpływie (impact_statement), którego CISA wymaga wtedy zamiast uzasadnienia. Czego nie wolno zrobić, to przyjąć założenia dla wygody.

Czy mogę wymagać SBOM od dostawcy, skoro CRA go do tego nie zobowiązuje?

Tak, ale podstawą jest umowa, a nie przepis. CRA nakazuje producentowi sporządzić wykaz i trzymać go w dokumentacji technicznej — nie przekazywać go klientom. Dla podmiotów objętych rozporządzeniem wykonawczym (UE) 2024/2690 dodatkowym argumentem jest pkt 6.1.2 lit. c załącznika, który wymaga, aby proces nabywania obejmował informacje opisujące elementy sprzętu i oprogramowania. Praktycznie warto wpisać do umowy trzy rzeczy: wykaz dla wydawanych wersji, zakres obejmujący zależności przechodnie i termin stanowiska po ujawnieniu krytycznej podatności. Przed podpisaniem to negocjacja, po podpisaniu — prośba.

Jak SBOM wiąże się z CRA?

Wykaz jest jednym z elementów dokumentacji technicznej producenta (załącznik VII) i podstawą realizacji obowiązku identyfikowania oraz dokumentowania komponentów i podatności z załącznika I część II pkt 1. Rozporządzenie nie wskazuje konkretnego formatu — doprecyzowanie pozostawiono aktom wykonawczym Komisji, a te na dzień publikacji tego materiału nie powstały. Warto też pamiętać o kolejności dat: obowiązek zgłaszania aktywnie wykorzystywanych podatności z art. 14 rusza 11 września 2026 r., a wymagania załącznika I — w tym wykaz składników — dopiero 11 grudnia 2027 r.

Od czego zacząć w małej firmie?

Od jednego artefaktu wystawionego do Internetu. Jeżeli sami go budujemy — od wykazu z procesu budowania; jeżeli nie, od skanu hosta albo obrazu, tak jak w opisanym wyżej pierwszym tygodniu na istniejącej flocie. Wygenerowanie wykazu, wgranie go do rejestru komponentów i sprawdzenie, co zwraca zapytanie o dowolną popularną bibliotekę, zajmuje kilka godzin i pokazuje różnicę wyraźniej niż jakiekolwiek opracowanie. Rozszerzanie zakresu ma sens dopiero wtedy, gdy pierwszy wykaz odświeża się bez udziału człowieka.

Źródła

Standardy i formaty

Minimalne elementy i praktyka wymiany

VEX i analiza wykorzystywalności

Wymagania prawne

Zdarzenia i analizy

Narzędzia

Podsumowanie

Wartość wykazu składników nie bierze się z samego jego istnienia. Bierze się z tego, że w momencie, w którym pojawia się opis krytycznej podatności, odpowiedź na pytanie „czy my tego używamy, gdzie i w jakiej wersji” jest zapytaniem, a nie akcją poszukiwawczą na kilka dni.

Trzy rzeczy decydują o tym, czy tak faktycznie będzie. Wykaz musi powstawać automatycznie, razem z artefaktem, bo dokument tworzony ręcznie starzeje się szybciej, niż powstaje. Musi obejmować zależności przechodnie, bo tam zwykle jest problem — zakres minimalny z CRA to najniższa poprzeczka, nie cel. Musi mieć jeden punkt zapytania, bo kilkaset plików bez rejestru to ta sama praca ręczna, tylko przeniesiona.

I jedna rzecz, o której warto pamiętać przy każdej rozmowie o wdrożeniu: wykaz składników nie zabezpiecza niczego. Jest źródłem danych, dzięki któremu decyzja o naprawie zapada szybciej i na podstawie faktów. Zabezpiecza dopiero to, co po tej decyzji następuje — aktualizacja komponentu, weryfikacja skutku i zapis, który przetrwa do następnego zdarzenia.

Jeżeli chcesz przełożyć ten model na konkretne środowisko, najbliżej temu materiałowi do bezpieczeństwa środowiska IT — uporządkowania ekspozycji, procesu obsługi podatności i dowodów działania kontroli. Stronę wykonawczą, czyli aktualizacje komponentów i okna serwisowe, obejmuje administracja serwerami Linux, a obserwację skutków zmian — monitoring infrastruktury IT.