Incydent Rust arrayref ostrzega przed zaufaniem do kodu uruchamianego przy buildzie
Złośliwe wydanie arrayref było online krócej niż dwie godziny, ale ujawniło większy problem: menedżery pakietów często uruchamiają kod zależności podczas builda.
Atak supply-chain na rustowy crate arrayref był krótki, wąski i mimo to ważny. Według Rust Security Response Team złośliwe wersje związane z arrayref, internment i append-only-vec usunięto z crates.io w oknach 86, 90 i 107 minut. Oficjalny blog Rust podkreśla, że legalny maintainer arrayref nie jest uznawany za złośliwego; robocza hipoteza to kompromitacja maszyny lub credentials. Szybka reakcja to dobra wiadomość.

To jednak nie cała historia. Dla Open Source Radar incydent jest istotny, bo dotyka pytania o package managers: jaki kod może uruchomić się przy budowaniu dependency, gdzie działa i z jakimi uprawnieniami? Rust nie jest npm, a crates.io nie jest chaotycznym rejestrem. Mimo to mała, stara i nudna zależność stała się ścieżką build-time execution.
arrayref nie jest modną biblioteką. Dokumentacja opisuje cztery macros do referencji array/slice. Właśnie dlatego to ważne: ryzyko może przyjść z drobnego utility, które od lat siedzi w transitive dependency graph.
Co się stało
Rust blog podaje, że 20 sierpnia 2026 zweryfikowano raport o złośliwym proc-macro1. [email protected] opublikowano o 07:15 UTC i usunięto o 08:41:40. [email protected] był online od 07:34:07 do 09:04:11. [email protected] od 07:37:49 do 09:25:24.
Usunięto też attacker-owned crates: proc-macro1, proc-macro-en, aovine, arone, aronenao, tinymember. Przywrócono legalne wersje maliciously yanked i zablokowano konto. GitHub Advisory Database opublikowało GHSA-jwh4-228v-r358 dla arrayref = 0.3.10, malicious code, bez patched version.
Mechanizm był prosty. SafeDep i inni opisują, że [email protected] dodał dependency na typosquatted proc-macro1, łatwe do pomylenia z proc-macro2. Złośliwy crate kopiował realny source proc-macro2, aby build wyglądał normalnie, podczas gdy build script działał.
Build script jest sednem. Cargo używa ich do native libraries, code generation, platform detection i konfiguracji. Ale oznacza to, że dependency może wykonać kod podczas builda. Jeśli dzieje się to na laptopie developera lub CI runner z tokens, SSH keys, cloud credentials albo publishing rights, nawet krótkie okno ma znaczenie.
Dlaczego krótko nie znaczy bezpiecznie
Nowoczesne CI jest szybkie, automatyczne i często pełne sekretów. Dependency update, scheduled build, cargo update, rebuild obrazu albo bot mogły uruchomić kod w oknie ekspozycji.
Raporty wskazują też, że starsze wersje arrayref były yanked, przez co złośliwa wersja mogła wyglądać jak naturalna ścieżka aktualizacji. Metadata i zachowanie registry są częścią attack surface.
Ostrożne stwierdzenie brzmi: nie każdy projekt używający arrayref został skompromitowany. Ale każdy system, który budował affected versions, powinien zostać potraktowany jako potencjalnie narażony do czasu sprawdzenia logs, artifacts i credentials.
Co Rust zrobił dobrze
Reakcja była szybka i publiczna: usunięcie crates, przywrócenie legalnych wersji, timelines, advisories, wskazówki do sprawdzenia cache Cargo, koordynacja RustSec i GitHub, blokada konta. Ważne było też nieoskarżanie legalnego maintainer bez dowodów.
Open source potrzebuje takich procedur. Incydenty się zdarzają; jakość response naprawia zaufanie. Registry potrzebuje takedown, yanking, security response, public advisories i jasnego rozróżnienia kompromitacji maintainer od złej woli.
Społeczność Rust szybko przeszła do system design: sandboxing build scripts, allowlists, registry anomaly detection, lockfiles, dependency culture, containers i microcrates. To właściwa rozmowa. Żaden ekosystem nie może ignorować trust boundaries package managera.
Niewygodne pytanie Cargo
Build scripts nie są błędem. npm ma postinstall, Python build backends, native packages configure scripts, Rust ma build.rs. Open source wybierał wygodę, portowalność i automatyzację. Atakujący widzą, że build systems uruchamiają się wcześnie i z dużymi uprawnieniami.
Pytanie nie brzmi, czy build scripts mają istnieć. Pytanie brzmi, czy każdy nowy albo zmieniony build script powinien mieć pełny dostęp domyślnie. Mała dependency może nagle dodać build dependency. Crate może pociągnąć typosquatted package. Build script może otworzyć sieć, czytać environment i dotykać plików.
Cargo issue “Build script allowlist mode” i goal sandboxed build scripts pokazują, że temat już istniał. Incydent dodaje pilność. Potrzebne będą warstwy: registry signals, allowlists, sandbox, dependency diffs, network-deny modes i lepsza kontrola yanks oraz owners.
Co sprawdzić teraz
Zespoły Rust powinny szukać [email protected], [email protected], [email protected] i usuniętych attacker crates w Cargo.lock, vendored dependencies, CI logs, caches i artifact provenance. Cache ma znaczenie, bo crate może pozostać po takedown.
Następnie przejrzeć buildy z 20 sierpnia 2026 w danych oknach: CI, self-hosted runners, workstations, release builders i image rebuilds. Jeśli build miał secrets, package tokens, cloud credentials, signing keys lub SSH material, należy rotować to, co mogło być narażone.
Sprawdź network egress. Wiele buildów nie potrzebuje szerokiego wyjścia po fetch zależności. Ephemeral runners, izolowane containers, egress policies i short-lived credentials obniżają wartość payloadów.
Narzędzia pomagają: cargo audit, advisories, cargo deny, cargo vet, scanners. Ale żadne nie zastępuje sandbox i least privilege.
Maintainers i registries
Maintainers powinni utwardzić publishing accounts: strong authentication, scoped tokens, least privilege, oddzielne release machines, alerty na yanks, owner changes i releases. Mały crate może być critical infrastructure.
Registries powinny traktować nietypowe zmiany jako signals: nowy build script w starym crate, typosquatted dependency, suspicious yanking, network behavior. Friction może oznaczać warning, delay, confirmation, scanning albo mocniejszy UI.
Tool authors mogą poprawić dependency diffs: nowe build scripts, proc macros, owners, native code, outbound network, yanked predecessors i nazwy podobne do znanych packages.
Nie tylko Rust
Porównania z npm i PyPI są przydatne, jeśli nie stają się tribalism. Rust ma strong type safety i poważną security culture. To nie usuwa registry compromise, stolen credentials, malicious build scripts ani social engineering.
Lekcja ogólna: samo czytanie source code nie wystarcza. Ważne jest kiedy kod się uruchamia. Dependency w lockfile to jedno. Dependency z build script na CI runner z release tokens to coś innego.
Co warto wypróbować
Przeglądaj Cargo.lock, używaj ephemeral runners, usuń long-lived secrets z general builds, ogranicz network, prowadź listę crates allowed to run build scripts. Dla critical software: sprawdź cargo vet, cargo deny, RustSec/GitHub alerts i scanners patrzące na build-time behavior.
Radar signal jest jasny: to test dla registries, lockfiles, advisories, CI i package managers. Reuse pozostaje siłą open source. Potrzebuje modelu zaufania, który traktuje build-time code jak prawdziwy kod.
Comments
Sign in to comment.
No comments yet.