En uvedligeholdt pakke er ikke en sårbarhed. Den er værre på én bestemt måde: når der først dukker en sårbarhed op i den, er der ingen til at rette den. Du venter ikke på en rettelse — du venter på noget, der ikke kommer.

Det er det fund, folk oftest afviser, og begrundelsen er til at forstå: intet er i stykker, intet bliver udnyttet, koden virker præcis som sidste år. Risikoen handler udelukkende om fremtiden, og det gør den nem at udskyde i det uendelige.

Den brugbare omformulering er, at et frafald fjerner en mulighed, du i stilhed regnede med. Hver eneste afhængighed i dit træ bærer en underforstået antagelse om, at hvis noget går galt, kommer der en opdatering. For en forladt pakke er den antagelse falsk, og det finder du ud af på det værst tænkelige tidspunkt.

Først: er den forladt, eller er den færdig?

Den skelnen betyder mere end noget andet her, og de fleste værktøjer får den galt.

Rigtig meget god software er ganske enkelt færdig. Et bibliotek på fyrre linjer, der polstrer en tekststreng, tjekker en type eller læser ét bestemt format, har ikke brug for commits. Det har ingen køreplan, fordi der ikke er mere arbejde. "Ingen udgivelse i tre år" beskriver både et sundt lille værktøj og et rådnende framework, og at behandle dem ens er præcis dét, der lærer folk at ignorere scanneren.

Signaler, der betyder, at den reelt er forladt, groft sorteret efter hvor entydige de er:

  • Vedligeholderen siger det. En npm-deprecation, et abandoned-flag på Packagist, et arkiveret repository, eller en README, der siger "dette projekt vedligeholdes ikke længere, brug X i stedet". Det er ikke en slutning — det er en udmelding, og det er det eneste fuldt pålidelige signal.
  • Åbne sikkerhedssager uden svar. Det stærkeste adfærdsmæssige bevis. En advarsel eller et indberettet hul, der ligger urørt i månedsvis, fortæller dig, hvad der ville ske med dit.
  • Pull requests, der hober sig op ugennemgåede. Folk prøver stadig; ingen tager imod.
  • Ingen udgivelse hen over et brud i økosystemet. En Node-pakke uden udgivelse hen over to store Node-versioner, eller en Python-pakke uden en build til den nuværende fortolkerudgave, er ikke færdig — den er blevet efterladt.
  • Én enkelt vedligeholder, der er blevet tavs alle vegne. Bus-faktoren var én, og bussen kom.

Læg mærke til, at ingen af dem er "sidste commit er længe siden" i sig selv. Alder er en anledning til at kigge, ikke en dom.

Hvorfor det er et sikkerhedsproblem og ikke bare hygiejne

Tre konsekvenser, og den tredje er den, folk undervurderer:

Den næste sårbarhed er permanent. Normalt bliver et hul offentliggjort, og en lappet version følger efter. Her bliver hullet offentliggjort, og der følger ingenting, så dine muligheder skrumper til at forke, lappe selv eller fjerne den under pres — og ingen af delene klarer du på en eftermiddag.

Den spærrer for andre opdateringer. En forladt pakke angiver stadig, hvilke versioner af sine egne afhængigheder den accepterer, og de grænser var aktuelle den dag, den sidst blev udgivet. De bliver til et loft. Opløseren nægter at give dig den nye hovedversion af et bibliotek, du tilfældigvis deler med den, og du får en peer-dependency-konflikt i npm eller en direkte opløsningsfejl i pip eller Maven. Overrides findes, og folk bruger dem, men en override er en beslutning om at køre en kombination, ingen har testet. Ét dødt bibliotek i bunden af træet kan holde et dusin levende tilbage, og sådan bliver et lille problem til et arkitektonisk.

En forladt pakke er et attraktivt mål. Det er den undervurderede del. En hvilende pakke med rigtige downloads og en inaktiv vedligeholder er præcis dét, en angriber leder efter, når de vil overtage en pakke, folk allerede stoler på — kontoen er ofte beskyttet af en gammel adgangskode, og ingen følger udgivelserne tæt nok til at opdage en mærkelig en. event-stream er det kanoniske tilfælde, og det begyndte præcis her: en vedligeholder, der ikke længere brugte pakken, overdrog den til den første frivillige, der meldte sig. Obligatorisk to-faktor-login på pakker med mange downloads har siden gjort den groveste udgave sværere, og det er en reel forbedring og ikke en løsning — det ændrer intet ved en overdragelse, vedligeholderen selv foretager.

De fire muligheder

1. Udskift den. Det rigtige svar, når der findes et vedligeholdt alternativ, og berøringsfladen er lille. Gør det bevidst, mens der ikke er ild i noget, og mens du stadig kan læse den kode, du erstatter. Prisen er kendt, og tidspunktet er dit.

2. Optag den. Er pakken lille — og det er overraskende mange — så kopiér koden ind i dit eget repository, med licens og kreditering — og tag ejerskabet. Det lyder som et tilbageskridt og er ofte rigtigt: fyrre linjer, du vedligeholder, slår fyrre linjer, ingen vedligeholder. Det fjerner samtidig en udførelsesvej ved installation, du ikke havde brug for.

3. Fork den. Relevant, når pakken er for stor at optage og for indlejret at udskifte. Vær klar over, hvad du skriver under på: nu vedligeholder du et bibliotek. Tjek først, om der allerede findes en fællesskabs-fork, for det gør der som regel ved udbredte forladte pakker, og at slutte sig til den er langt billigere end at starte en.

4. Acceptér den — bevidst og på skrift. Et fuldstændig legitimt valg for en lille, stabil, velforstået pakke i en position med lav risiko. Det ord, der betyder noget, er bevidst: skriv beslutningen ned, notér hvem der traf den og hvorfor, og sæt en betingelse, der åbner den igen — en offentliggjort sårbarhed, en ændring i, hvordan pakken bliver brugt. En accepteret risiko er en beslutning. Et ignoreret fund er et uheld, der ikke er sket endnu.

Sådan sker det sjældnere

Du kan ikke forhindre vedligeholdere i at gå videre — de skylder dig ingenting, og det meste open source er ulønnet arbejde. Det, du kan, er at vælge med fejltilstanden for øje.

Foretræk pakker, hvor mere end én person kan udgive. Foretræk dem under en organisation eller en fond frem for en personlig konto. Vær ærlig om, hvorvidt en afhængighed overhovedet er værd at have: en pakke, der sparer dig tredive linjer, er ikke indlysende et permanent forsyningskædeforhold værd — og refleksen til at hente i stedet for at skrive er den samme refleks, der gør træet seks hundrede dybt.

Og hold øje med dem, du har, for den her status ændrer sig, uden at din kode gør. Det er den egenskab, der gør en engangsgennemgang ubrugelig her.

Hvordan ser jeg, om en pakke er forladt eller bare færdig?

Alder alene fortæller dig ingenting — et lille bibliotek, der gør én ting, kan være færdigt og ikke have brug for commits i årevis. De entydige signaler er udtrykkelige udmeldinger: en npm-deprecation, et abandoned-flag på Packagist, et arkiveret repository eller en README, der siger, at projektet ikke vedligeholdes længere. De stærkeste adfærdsmæssige signaler er åbne sikkerhedssager uden svar, pull requests, der hober sig op ugennemgåede, og ingen udgivelse hen over et brud i det omgivende økosystem.

Hvorfor er en uvedligeholdt afhængighed en sikkerhedsrisiko?

En uvedligeholdt afhængighed er en sikkerhedsrisiko, fordi den næste sårbarhed, der bliver fundet i den, er permanent: normalt bliver et hul offentliggjort, og en lappet version følger efter, men her følger der ingenting, så mulighederne skrumper til at forke, lappe selv eller fjerne den under tidspres. Den fastlåser samtidig gamle versioner af sine egne afhængigheder og holder andre opdateringer tilbage. Og en hvilende pakke med rigtige downloads og en inaktiv vedligeholder er et attraktivt mål for kontoovertagelse, fordi ingen følger dens udgivelser tæt.

Hvad gør jeg ved en forladt afhængighed?

Der er fire muligheder. Udskift den med et vedligeholdt alternativ, hvilket er rigtigt, når berøringsfladen er lille, og du kan nå det, mens der ikke er ild i noget. Optag den i din egen kodebase med dens licens, hvis den er lille nok, eftersom kode, du vedligeholder, slår kode, ingen vedligeholder. Fork den, hvis den er for stor at optage, men tjek først, om der allerede findes en fællesskabs-fork. Eller acceptér den bevidst og på skrift, med en nedskrevet begrundelse og en betingelse, der åbner beslutningen igen.

Hvordan undgår jeg at afhænge af pakker, der bliver forladt?

Foretræk pakker, hvor mere end én person kan udgive, og dem, der ligger hos en organisation eller en fond i stedet for en personlig konto. Vær ærlig om, hvorvidt en afhængighed overhovedet fortjener sin plads, eftersom en pakke, der sparer tredive linjers kode, ikke indlysende er et permanent forsyningskædeforhold værd. Hold derefter øje med det, du allerede har, for vedligeholdelsesstatus ændrer sig, uden at din kode gør — og netop derfor hjælper en engangsgennemgang ikke her.

Hvor CodeControl passer ind

CodeControl tjekker hver afhængighed mod de udtrykkelige signaler først — npm-deprecation, abandoned på Packagist, arkiverede repositories — før den falder tilbage på manglende aktivitet, så et lille færdigt værktøj ikke bliver meldt som et rådnende framework. Fundene bærer begrundelsen med, så du kan skelne de to uden selv at gå på jagt. Og fordi det at kvittere for et fund kræver en skreven begrundelse, bliver "det her har vi accepteret bevidst" skrevet ned i stedet for husket — og åbnet igen, når der bliver offentliggjort en sårbarhed imod den.