Přeskočit na hlavní obsah
Zpět na přehled

NPM Apokalypsa 2025: Jak klidně spát, když se hroutí ekosystém

2025-12-24
npmsecurityrenovatedependenciesvulnerabilities
4 min čtení

Pokud sledujete dění ve světě JavaScriptu, nemohlo vám to uniknout. Letošní rok byl pro bezpečnost NPM ekosystému naprostá katastrofa.

Nebavíme se o jednotkách případů. Bavíme se o stovkách balíčků, které byly kompromitovány. Útočníci získali přístup k účtům maintainerů (často přes sociální inženýrství nebo uniklé tokeny) a do legitimních, hojně používaných knihoven propašovali škodlivý kód.

Některé z těchto balíčků měly miliony stažení týdně. Představte si to: v pondělí ráno přijdete do práce, spustíte npm install, a aniž byste cokoliv tušili, stahujete si do projektu malware, který krade vaše ENV proměnné nebo injectuje kryptominer do prohlížečů vašich uživatelů.

Je to děsivé. A upřímně – pokud spoléháte jen na štěstí, je to jen otázka času, kdy to trefí i vás.

Tři vrstvy manuální obrany

První instinktivní reakce je: "Přestanu používat NPM!" To je sice hezká myšlenka, ale v moderním frontend vývoji asi tak reálná, jako chtít postavit mrakodrap jen pomocí kladiva a hřebíků. Bez ekosystému Reactu, TanStacku nebo Tailwindu se dnes neobejdeme.

Existují ale kroky, které dělám, abych riziko minimalizoval:

1. Minimalismus a Forkování

Než přidám novou závislost, ptám se: "Opravdu potřebuji celou knihovnu na to, abych naformátoval datum?" Pokud je to malá utilita, raději si ji napíšu sám. Pokud je to složitější knihovna, která ale obsahuje spoustu balastu, často udělám fork. Vezmu si jen tu část kódu, kterou potřebuji, a vložím ji přímo do svého repozitáře. Tím odstřihnu pupeční šňůru od budoucích aktualizací (které mohou být infikované).

2. Zákaz skriptů (ignore-scripts)

Většina útoků se spoléhá na tzv. postinstall skripty. To jsou příkazy, které se spustí automaticky hned po stažení balíčku. Útočníci je milují – je to ideální místo, kam schovat curl, který odešle vaše .env soubory na jejich server.

Obrana je jednoduchá. Do kořene projektu (k souboru package.json) přidejte soubor .npmrc s tímto obsahem:

ignore-scripts=true

Tím globálně zakážete spouštění těchto skriptů. Ano, občas to rozbije instalaci nějakého legitimního nástroje (třeba esbuild nebo cypress), ale to se dá vyřešit whitelistováním konkrétních balíčků. Bezpečnost za to stojí.

Automatizace: Když člověk nestačí

Manuální kroky jsou fajn, ale mají jednu slabinu: mě. Já zapomínám. Já nemám čas každé ráno číst bezpečnostní reporty a kontrolovat, jestli verze lodash 4.17.21 není náhodou děravá.

Dlouho jsem hledal nástroj, který by mi hlídal záda. Potřeboval jsem něco, co:

  1. Běží automaticky (CI/CD).
  2. Zná databázi zranitelností (GitHub Security Advisories, OSV).
  3. Nebude mě otravovat zbytečnými aktualizacemi, ale bude křičet, když jde o bezpečnost.

Vítězem se stal Renovate Bot.

Můj "Security-First" Config

Renovate většina lidí zná jako nástroj, který automaticky zvedá verze balíčků. "Vyšla nová verze Reactu? Tady máš PR."

Já ho ale používám jinak. Na stabilních projektech nechci, aby mi bot "rozbíjel" aplikaci aktualizacemi minor verzí, které nepotřebuji. Chci, aby mlčel a ozval se pouze v případě, že moje aktuální verze obsahuje bezpečnostní díru.

Tohle je konfigurace, kterou aktuálně testuji a která mi dává klidné spaní:

{
  "$schema": "[https://docs.renovatebot.com/renovate-schema.json](https://docs.renovatebot.com/renovate-schema.json)",
  "extends": [
    "group:turboMonorepo",
    ":semanticCommits"
  ],
  "timezone": "Europe/Prague",
  "prConcurrentLimit": 10,
  "prHourlyLimit": 0,
  "dependencyDashboard": true,
  "dependencyDashboardApproval": false,
  // Tady začíná magie: Zapínáme Security Alerts
  "vulnerabilityAlerts": {
    "enabled": true,
    "labels": [
      "security",
      "vulnerability"
    ]
  },
  "osvVulnerabilityAlerts": true,
  "automerge": false,
  "rangeStrategy": "pin",
  "schedule": [
    "at any time"
  ],
  // Pravidlo, které vypíná VŠECHNY aktualizace...
  "packageRules": [
    {
      "description": "Disable all non-security updates",
      "matchUpdateTypes": [
        "major",
        "minor",
        "patch",
        "pin",
        "digest",
        "lockFileMaintenance",
        "rollback",
        "bump",
        "replacement"
      ],
      "enabled": false
    }
  ]
}

Jak to funguje?

Všimněte si sekce packageRules. Ta explicitně říká: "Zakaž (enabled: false) všechny typy aktualizací (major, minor, patch...)."

Kdybych skončil tady, Renovate by nedělal nic. Ale protože mám nahoře zapnuté vulnerabilityAlerts a osvVulnerabilityAlerts, Renovate stále kontroluje databáze zranitelností.

Výsledek?

  • Vyjde axios v1.8.0 (nová feature)? Ticho. Renovate mě neruší.
  • Zjistí se, že axios v1.7.0 má bezpečnostní díru? ALARM. Renovate okamžitě vytvoří Pull Request s opravou na bezpečnou verzi a otaguje ho jako security.

Tento config stačí zapojit do GitHub/GitLab CI pipeline a nastavit spouštění jednou denně (nebo každou hodinu).

Díky tomu vím, že i když já spím, můj repozitář je porovnáván s nejnovějšími databázemi hrozeb. Není to 100% ochrana (ta neexistuje), ale je to mnohem lepší, než doufat, že se mi to vyhne.