Signerad. Legitim. Förgiftad.

Om supply chain-attacker, SBOM och varför ingredienslistan inte räcker.

En genomsnittlig Node.js-applikation har över 1 000 transitiva beroenden. De flesta utvecklare kan namnge kanske tjugo av dem.

Resten är npm-paket från okända underhållare, Python-bibliotek som senast granskades 2019, GitHub Actions skrivna av någon som bytte bransch för tre år sedan, och CDN-beroenden som pekar mot en domän någon annan nu äger. Och sedan 2026: kod som din AI-assistent valde åt dig, utan att fråga, medan du fokuserade på något annat.

Vi pratar om “våra system”. Våra applikationer. Vår kod. Men vi knappt äger en tredjedel av det vi kallar vårt.

Det är inte slarv. Det är hur modern mjukvaruutveckling fungerar. Återanvändning, open source, snabb iteration. Produktivt, rationellt och i grunden bra.

Men det är också den exakta attackytan angriparna letar efter.


Inte en attack mot din kod. En attack mot din tillit.

Det som skiljer supply chain-attacker från allt annat är att de inte bryter sig in. De smiter in.

De komprometterar inte ditt system. De komprometterar något du litar på, som litar på något du litar på.

Och det tar ofta månader innan någon märker det.

Titta på XZ Utils. Tre år. Tre år av tålmodigt arbete — bidrag, buggfixar, hjälpsamhet — för att bygga förtroende nog att till slut plantera en bakdörr med CVSS 10.0 i en av grundkomponenterna i halva internet. Angriparen var inte slarvig. Angriparen var metodisk på ett sätt som gör de flesta säkerhetsteam generade. Och det enda som stoppade den var att en utvecklare märkte att SSH-anslutningar var 400 millisekunder långsammare än normalt. 👉 För en konkret och nästan obehagligt tydlig bild av hur nära vi varit en global supply chain-katastrof, se denna dokumentär: The Internet Was Weeks Away From Disaster

Polyfill.io? Domänköp. En kinesisk aktör köper domänen, ärver förtroendet från 100 000 webbplatser som länge sedan inkluderade ett script-tag i sin HTML, och börjar injicera JavaScript i realtid. Ingen bröt sig in. Ingen hackade något. De köpte nyckeln.

tj-actions i mars 2025? GitHub Action. Tagg förgiftad. 23 000+ repositorier läcker sina CI/CD-hemligheter i klartext i loggarna. Inte för att någon var dum. För att ingen ifrågasatte varför de litade på en extern action de aldrig hade granskat.

Och Next.js, mars 2025. CVSS 9.1. Ett internt HTTP-header som aldrig var tänkt att exponeras externtx-middleware-subrequest — visade sig gå att manipulera av vem som helst. En angripare skickar rätt header-värde och hoppar rakt förbi all autentisering, all sessionskontroll, all middleware-logik. Versioner 11 till 15. Miljontals self-hostade applikationer. Proof-of-concept publicerat inom 48 timmar. NCSC i Storbritannien gick ut med en varning. Det enda som skyddade dig var om du råkade hosta på Vercel — eller om någon i ditt team råkade läsa rätt säkerhetsnyhetsbrev den veckan.

Axios, mars 2026. 83 miljoner nedladdningar i veckan. Underhållarkontot kapas. En trojaniserad version distribueras via den officiella kanalen. Signerad. Legitim. Förgiftad.

Det är mönstret. Inte tekniska brister i din kod. Förtroendebrister i din supply chain.


Attackerna 2023–2026 i korthet

Det här är inte ett hypotetiskt hot. Det är en kronologi.

AttackÅrAngripareAngreppsvektorPåverkan
3CX Desktop App2023Lazarus Group (DPRK)Build-miljö komprometterad, signerad trojaniserad installerGlobala Fortune 500-kunder
MOVEit Transfer2023Cl0p ransomwareSQL injection, web shell i databaserTusentals org., myndigheter, banker
JetBrains TeamCity2023Cozy Bear (SVR)Auth-bypass CVE, RCE mot CI/CD-plattformBuild pipelines, downstream-mjukvara
CircleCI2023OkändIntern kompromiss, hemligheter exponeradeCI/CD-kunder, produktionsmiljöer
Discord/Colorama2024OkändSkadlig PyPI-klon av populärt paket170 000 Discord-botsutvecklare
XZ Utils2024JiaT75 (nation-stat)3 år social engineering, bakdörr i liblzmaLinux-distributioner, SSH — CVSS 10.0
Polyfill.io2024Funnull (Kina)Domänövertagande, dynamisk JS-injektion100 000+ webbplatser
Next.js (CVE-2025-29927)2025OkändAuth-bypass via intern header x-middleware-subrequest — hoppar förbi all middleware-säkerhetMiljontals self-hostade Next.js 11–15-applikationer — CVSS 9.1
tj-actions2025Kopplat till DPRKGitHub Action-tagg förgiftad, secrets i loggar23 000+ GitHub-repositorier
GlassWorm2025–2026Rysktalande aktörOsynliga Unicode-tecken döljer kod, blockchain som C2400+ komprometterade komponenter
Axios (npm)2026BlueNoroff/LazarusUnderhållarkonto kapat, RAT injicerat~83M veckovisa nedladdningar

Antal supply chain-attacker fördubblades sedan april 2025. Oktober 2025 satte rekord med 41 registrerade incidenter. Skadlig kod i open source-repositorier ökade med 73% under 2025.

Det är inte “om” du påverkas. Det är “när” du upptäcker det. Och ofta: för sent.


Det nya problemet: AI vet inte vad den installerar heller

Det här var problemet 2022.

En människa hittade ett bibliotek. Ingen ifrågasatte. Ingen dokumenterade. Det hamnade i package.json.

Nu är det 2026. Och samma sak händer — fast i industriell skala, utan att en människa ens var inblandad.

Demokratiseringen av mjukvaruutveckling är på riktigt. Vibe coding fungerar. En person utan djup teknisk bakgrund kan promptomvandla en idé till ett körande system på en eftermiddag. Det är genuint bra. Det sänker trösklar, frigör kreativitet och gör att fler kan bygga.

Men det finns ett pris. Och priset är osynlighet.

När du vibe-codar med en AI-assistent och säger “bygg en funktion som hämtar data från det här API:t” — väljer modellen paket åt dig. Den installerar beroenden. Den väljer bibliotek baserat på vad den tränat på, vad som var populärt när träningsdatan skapades, vad som ser rimligt ut. Inte baserat på din organisations säkerhetspolicy. Inte baserat på en CVE-lista. Inte baserat på vad ni faktiskt har godkänt.

Det är inte ett fel i modellen. Det är ett systemfel i hur vi tänker på AI-genererad kod.

Och det eskalerar med agentisk AI.

En autonom agent som får i uppgift att “sätta upp ett backend-API” gör precis det. Den scaffoldar ett projekt, väljer ett ramverk, drar in tjugo beroenden, konfigurerar en CI/CD-pipeline — kanske med en GitHub Action från en extern repo den ansåg trovärdig — och levererar ett fungerande system. Snabbt. Utan att fråga.

Det här är inte ett hypotetiskt scenario. Det är hur Claude Code, Cursor Agents, Codex och liknande verktyg fungerar just nu, idag, i produktionsmiljöer.

Resultatet är en ny kategori av beroenden: AI-introducerade beroenden. De som ingen människa aktivt valde. De som inte syns i en arkitekturreview. De som inte har ett namn i “Beslut och ägarskap”-kolumnen — för att ingen tog ett beslut. En modell gjorde en avvägning baserat på sannolikhet, och sedan byggde du vidare.

Det är det gamla problemet i ny kostym. Skillnaden är hastigheten och volymen.

En mänsklig utvecklare introducerar kanske ett nytt beroende i veckan om det är en intensiv sprint. En agent kan introducera tjugo på en timme. Och om agenten kör i ett automatiserat flöde — ett command, ett webhook, ett schemalagt jobb — kan det hända utan att någon ens tittar på ett diff.

GlassWorm-kampanjen som komprometterade 400+ komponenter under 2025–2026 använde Unicode-tecken osynliga för mänskliga ögon. Men det finns en parallell risk som ingen behöver plantera: beroenden som AI introducerar är per definition osynliga för arkitekturstyrning om du inte aktivt tittar.

Det finns ingen illvilja i modellen. Det finns bara avsaknad av kontext om vad din organisation faktiskt tillåter.

Och det är exakt det som arkitekturstyrning och SBOM måste hantera nu — inte bara det som dina utvecklare installerade, utan det som din AI installerade å dina vägnar.


SBOM: Ingredienslistan du inte har

En Software Bill of Materials är i grunden enkel.

Det är en lista. Vad innehåller din mjukvara? Vilka komponenter, vilka versioner, vilka beroenden — inklusive de transitiva, de du aldrig aktivt valde utan fick på köpet för att paketet du ville ha råkade vilja ha dem också.

Analogin med livsmedel är träffande på ett obehagligt sätt. Du vet vad som är i din yoghurt. Inte för att du frågade fabriken — för att det finns ett lagkrav som tvingade dem att berätta. EU:s Cyber Resilience Act är på väg att göra samma sak för mjukvara. Det var länge sedan det borde ha hänt.

Med en uppdaterad SBOM kan du faktiskt svara på frågan: “Använder vi Log4j?” eller “Är vi exponerade för det här?” inom minuter istället för veckor. Det är impact analysis på riktigt. Inte en konsult som manuellt går igenom repositorier.

Men här är problemet med de flesta organisationer:

De har ingen SBOM.
Eller de har en gammal SBOM.
Eller de har en SBOM som ingen vet var den är.
Eller de har en SBOM som ett verktyg genererade en gång och som ingen förstår.

En SBOM utan livscykel är som en brandvarnare utan batteri. Den ser bra ut. Den gör ingenting.


SBOM.md: Från JSON-export till levande dokument

Här är en detalj som sällan diskuteras.

SBOM-formaten SPDX och CycloneDX är utmärkta. Maskinläsbara. Standardiserade. Integrerbara med verktyg. Genereras automatiskt av Syft, Trivy, cdxgen.

Men ingen människa sitter och läser ett SPDX-dokument på fritiden.

Och det är ett problem. För en SBOM som bara är en artefakt i en pipeline — en JSON-fil som sparas bredvid bygget och aldrig öppnas av en människa — är fortfarande halvblint säkerhetsarbete.

Idén med SBOM.md är enkel: varje kritiskt system bör ha en läsbar, versionshanterad, mänskligt begriplig SBOM som lever i samma Git-repo som koden. Uppdateras vid release. Ägs av teamet. Kopplad till arkitekturbesluten bakom varje beroende.

Inte istället för maskinläsbar SBOM. Bredvid den.

En ingredienslista som en människa kan läsa är inte en lyx. Det är grundläggande ansvar för vad du bygger.

Så här kan en SBOM.md se ut

Det behöver inte vara komplicerat. Det behöver vara sant, läsbart och uppdaterat. Här är ett realistiskt exempel:

markdown

# SBOM — Software Bill of Materials
## MinTjänst v2.5.1

## Metadata
| Fält         | Värde                          |
|--------------|-------------------------------|
| Produkt      | MinTjänst                      |
| Version      | 2.5.1                          |
| Genererad    | 2026-04-02 (syft + manuell)   |
| Kontakt      | security@organisation.se       |
| Nästa review | 2026-07-01                     |

---

## Direkta beroenden

| Komponent        | Version | Typ       | Licens     | SHA-256   | CVE-status          |
|------------------|---------|-----------|------------|-----------|---------------------|
| spring-boot      | 3.2.4   | Framework | Apache-2.0 | a1b2c3d4  | Inga kända          |
| log4j-core       | 2.17.1  | Library   | Apache-2.0 | e5f6g7h8  | CVE-2021-44228 ✓    |
| jackson-databind | 2.16.1  | Library   | Apache-2.0 | i9j0k1l2  | Inga kända          |
| react            | 18.2.0  | Framework | MIT        | q7r8s9t0  | Inga kända          |
| axios            | 1.7.9   | Library   | MIT        | u1v2w3x4  | Inga kända          |

---

## Transitiva beroenden (urval)

| Komponent   | Version | Direkt beroende av | Licens     |
|-------------|---------|---------------------|------------|
| spring-core | 6.1.5   | spring-boot         | Apache-2.0 |
| spring-web  | 6.1.5   | spring-boot         | Apache-2.0 |

---

## Beroendegraf

- **MinTjänst 2.5.1**
  - spring-boot 3.2.4
    - spring-core 6.1.5
    - spring-web 6.1.5
      - jackson-databind 2.16.1
  - react 18.2.0
    - axios 1.7.9

---

## Aktiva sårbarheter

| CVE-ID         | Nivå          | Komponent  | Status  | Åtgärd              |
|----------------|---------------|------------|---------|---------------------|
| CVE-2021-44228 | KRITISK (10.0)| log4j-core | Patchad | Uppgraderad 2.17.1  |

---

## Beslut och ägarskap

| Beroende    | Varför?                              | Risk      | Ägare          | Datum      |
|-------------|--------------------------------------|-----------|----------------|------------|
| axios       | HTTP-klient, etablerad standard      | Låg       | [Namn]         | 2025-01-15 |
| log4j-core  | Legacy, kvar av historiska skäl      | Medel     | [Namn]         | 2024-06-01 |
| got         | ⚠️ AI-introducerat (Claude Code)     | Okänd     | Ej tilldelad   | Granskas   |

---

## Godkännanden

| Roll               | Namn   | Datum      |
|--------------------|--------|------------|
| Säkerhetsarkitekt  | [Namn] | 2026-04-02 |
| Systemägare        | [Namn] | 2026-04-02 |

Notera den sista tabellen. Beslut och ägarskap. Det är den kolumnen de flesta glömmer — och den enda som svarar på varför ett beroende finns.


Prompt: Generera SBOM.md-struktur med AI

Vill du låta en AI skapa strukturen åt dig för ett specifikt system? Här är en prompt som fungerar:

Du är en erfaren säkerhetsarkitekt med djup kunskap om supply chain-säkerhet 
och SBOM (Software Bill of Materials).

Skapa en komplett SBOM.md för följande system:

**System:** [SYSTEMNAMN]
**Teknikstack:** [ex. Node.js, React, PostgreSQL, Redis]
**Miljö:** [ex. AWS, Kubernetes, Docker]
**Kritikalitet:** [ex. Hög — hanterar personuppgifter och betalningar]

Strukturen ska innehålla:
1. Metadata (produkt, version, datum, kontakt, nästa review)
2. Direkta beroenden med kolumner: Komponent, Version, Typ, Licens, 
   SHA-256 (placeholder), CVE-status
3. Transitiva beroenden (de vanligaste för angiven stack)
4. Beroendegraf i trädstruktur
5. Aktiva sårbarheter (känd historik för angiven stack)
6. Beslut och ägarskap — VIKTIGT: föreslå rimliga motiveringar 
   för varje beroende baserat på stacken
7. Godkännandetabell med roller

Prioritera läsbarhet för människor. Använd Markdown-tabeller.
Flagga beroenden med känd riskhistorik (log4j, axios, openssl etc.) tydligt.
Inkludera en kommentar i toppen med instruktioner för hur filen 
ska uppdateras i CI/CD.

Justera [SYSTEMNAMN], [teknikstack] och [kritikalitet] — resten sköter sig.


Agent: Inventera och populera SBOM.md automatiskt

En AI-agent kan göra hela inventeringen åt dig om du ger den rätt verktyg och instruktioner. Här är ett agent-prompt för att köra en faktisk inventering och populera filen:

Du är en SBOM-agent med tillgång till bash, filsystemet och internet.
Ditt mål är att inventera ett mjukvaruprojekt och skapa en komplett SBOM.md.

## Steg 1 — Identifiera teknikstack
- Läs package.json, requirements.txt, pom.xml, go.mod, Gemfile, 
  eller motsvarande beroendedefinitioner i projektets rot
- Identifiera runtime-miljö (Node, Python, Java, Go, Ruby etc.)
- Lista alla direkta beroenden med version

## Steg 2 — Generera maskinläsbar SBOM
Kör ett eller flera av följande kommandon beroende på stack:
  syft . -o cyclonedx-json > sbom.cdx.json
  syft . -o spdx-json > sbom.spdx.json
  trivy fs . --format cyclonedx --output sbom.cdx.json

## Steg 3 — Sårbarhetsscan
Kör:
  trivy fs . --severity HIGH,CRITICAL
  grype sbom:./sbom.cdx.json
Notera alla CVE:er med CVSS >= 7.0

## Steg 4 — Hämta metadata
För varje direkt beroende:
- Hämta senaste version från paketregistret (npm, PyPI, Maven Central)
- Jämför med installerad version — flagga om outdated
- Hämta licensinformation
- Beräkna SHA-256 på paketfilen om möjligt

## Steg 5 — Bygg SBOM.md
Skapa filen enligt denna struktur: [klistra in SBOM.md-mallen ovan]

## Steg 6 — Flagga risker
Markera explicit:
- Beroenden utan känd underhållare (senaste commit > 2 år)
- Beroenden med historik av kritiska CVE:er
- Transitiva beroenden fler än 3 nivåer djupa
- Externa CDN-beroenden som inte är versionspinnade
- Beroenden troligen introducerade av AI-verktyg (Cursor, Claude Code, 
  Copilot etc.) — identifieras via git log: commits av bot-konton, snabba 
  commit-sekvenser utan PR-review, eller package.json-ändringar utan 
  tillhörande arkitekturkommentar i commit-meddelandet

## Output
Spara SBOM.md i projektets rot.
Skriv en kort sammanfattning: antal komponenter, antal flaggade risker, 
rekommenderad åtgärd.

Starta med att lista vilka beroendedefinitionsfiler du hittar i projektet.

Det här funkar direkt i Claude Code, Cursor eller vilken agent-miljö som helst med filsystemsåtkomst. Kör det en gång manuellt. Lägg sedan in det i CI/CD som ett steg vid varje release.


Det SBOM inte svarar på

Och nu till den obekväma delen.

SBOM svarar på: Vad innehåller vår mjukvara?

Det är en viktig fråga. Men det är inte den enda viktiga frågan.

Den svarar inte på:

  • Varför finns det här beroendet?
  • Är det rimligt att vi har det?
  • Vem tog beslutet?
  • Vilken risk accepterade vi när vi lade till det?

Och det är precis där de flesta organisationer faller.

Beroenden smyger in. En utvecklare hittar ett bibliotek som löser ett problem. Ingen ifrågasätter. Ingen dokumenterar varför. Ingen äger beslutet. Det hamnar i package.json och glöms bort tills det dyker upp i en CVE tre år senare — och ingen längre vet varför det finns där.

CrowdStrike-kraschen 2024 är det perfekta exemplet. Det var inte en attack. Det var inte en sårbarhet i traditionell mening. Det var ett arkitekturbeslut: kernel-access, auto-update, ingen isolering. Och det beslutet ägdes aldrig av någon på ett sätt som hade kunnat ifrågasätta det. Resultatet var den största IT-kraschen i historien, orsakad av en ogiltig konfigurationsfil.

Inte ett hack. Ett designbeslut utan ägarskap.


Arkitekturstyrning: Frågan efter ingredienslistan

Det som saknas är kontexten till SBOM:en.

Arkitekturstyrning — vilket låter tungt men i praktiken betyder att någon faktiskt äger och motiverar sina beroendebeslut — svarar på frågorna SBOM inte kan ställa.

Varför har vi det här beroendet? Vilken alternativ finns? Vilken risk accepterar vi? Vem äger beslutet?

Det är inte byråkrati. Det är minne.

Organisationen glömmer. Inte för att folk är slarviga, utan för att folk slutar, projekt byter ägare, system överlever sina skapare. Utan dokumenterat beslutsägarskap är supply chain-risken osynlig tills den redan materialiserats.

SBOM ger dig transparens. Arkitekturstyrning ger dig kontext. Tillsammans ger de dig kontroll.

Teknisk sanning plus organisatoriskt ansvar. Det är kombinationen som faktiskt fungerar.


Vad du bör göra (utan att skapa ännu ett ramverk)

Generera SBOM i CI/CD. Varje bygge. Spara per release. Versionera det. Kräv det från leverantörer — det är rimligt och snart ett regulatoriskt krav ändå.

Lägg till SBOM.md per kritiskt system. Mänskligt läsbar. I Git. Uppdateras vid release. Det behöver inte vara vackert — det behöver vara sant.

Koppla beroenden till beslut. För varje nytt beroende av vikt: varför? Vilken risk? Vem äger det? Det behöver inte ta lång tid. Det behöver bara hända.

Minimera beroendeytans storlek. Det är 2026 och det stämmer fortfarande: ju mindre kod, desto mindre attackyta. Välj bort bibliotek du kan skriva tio rader för. Det är inte alltid rätt — men det är alltid en fråga värd att ställa.

Granska vad din AI installerar. Sätt upp en policy för AI-verktyg i din organisation: vilka paketregister är tillåtna, vilka beroenden kräver manuell granskning, och — viktigast — ingen agent får merga till main utan att en SBOM-diff har granskats. Det låter som byråkrati. Det är ett säkerhetsnät för en ny kategori av risker du inte kan se med blotta ögat.


Tillit är den nya attackytan

Vi pratar om Zero Trust som om det vore ett nätverks-koncept.

Men vi har fortfarande Full Trust i vår supply chain.

Vi litade på npm-paketet. Som litade på beroendets underhållare. Som litade på en domän som bytte ägare. Som litade på en GitHub Action vi aldrig läste. Och nu låter vi en AI-agent välja ramverk, installera beroenden och konfigurera pipelines — i ett flöde ingen människa granskade — och kallar det produktivitet.

Det är inte ett teknikproblem. Det är ett organisatoriskt minnesproblem som nu körs på autopilot.

Du vet förmodligen inte exakt vad din mjukvara är gjord av just nu. Du vet troligtvis inte heller vad din AI byggde igår.

Båda är ett bra ställe att börja.

Och om någon frågar vad du jobbar med nu?

SCABOM!!

Supply Chain Awareness + SBOM. Säg det tillräckligt högt så låter det som precis vad det är.


SBOM säger vad du har byggt. Arkitektur säger varför du gjorde det. Det är först när du förstår båda — inklusive det din AI valde åt dig — som du faktiskt har kontroll. Och inte bara en ingredienslista ingen läser.